20170707 IO部分和NIO部分感觉讲的有点不太好理解,没有细看。有一篇博客讲的挺详细的,有时间可以去瞅瞅 http://www.cnblogs.com/rollenholt/archive/2011/09/29/2195730.html
- 18.2 输入和输出
编程语言的I/O类库中常使用流这个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。“流”屏蔽了实际的I/O设备中处理数据的细节。
通过继承,任何自Inputstream或Reader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。同样,任何自OutputStream或Writer派生而来的类都含有名为write()的基本方法,用于写入单个字节或者字节数组。
- 18.2.1 InputStream类型
InputStream的作用是用来表示那些从不同数据源产生的输入的类。包括
名称 | 类 | 功能 |
---|---|---|
字节数组 | ByteArrayInputStream | 允许将内存的缓冲区当做InputStream |
String对象 | StringBufferInputStream | 将String转换成InputStream |
文件 | FileInputStream | 用户从文件中读取信息 |
管道,工作方式与实际管道相似,即从一端输入,从另一端输出 | PipedInputStream | 产生用于写入相关PipedOutputStream的数据,实现管道化概念 |
合并流 | SequenceInputStream | 将两个或多个InputStram对象转成单一InputStram |
抽象类,作为装饰器的接口 | FilterInputStream | 抽象类,作为装饰器的接口 |
一个PipedInputStream的例子
http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html
/** * 消息发送类 * */ class Send implements Runnable{ private PipedOutputStream out=null; public Send() { out=new PipedOutputStream(); } public PipedOutputStream getOut(){ return this.out; } public void run(){ String message="hello , Rollen"; try{ out.write(message.getBytes()); }catch (Exception e) { e.printStackTrace(); }try{ out.close(); }catch (Exception e) { e.printStackTrace(); } } } /** * 接受消息类 * */ class Recive implements Runnable{ private PipedInputStream input=null; public Recive(){ this.input=new PipedInputStream(); } public PipedInputStream getInput(){ return this.input; } public void run(){ byte[] b=new byte[1000]; int len=0; try{ len=this.input.read(b); }catch (Exception e) { e.printStackTrace(); }try{ input.close(); }catch (Exception e) { e.printStackTrace(); } System.out.println("接受的内容为 "+(new String(b,0,len))); } } /** * 测试类 * */ class hello{ public static void main(String[] args) throws IOException { Send send=new Send(); Recive recive=new Recive(); try{ //管道连接 send.getOut().connect(recive.getInput()); }catch (Exception e) { e.printStackTrace(); } new Thread(send).start(); new Thread(recive).start(); } }
一个SequenceInputStream的例子
File file1 = new File("d:" + File.separator + "hello1.txt"); File file2 = new File("d:" + File.separator + "hello2.txt"); File file3 = new File("d:" + File.separator + "hello.txt"); InputStream input1 = new FileInputStream(file1); InputStream input2 = new FileInputStream(file2); OutputStream output = new FileOutputStream(file3); // 合并流 SequenceInputStream sis = new SequenceInputStream(input1, input2); int temp = 0; while((temp = sis.read()) != -1){ output.write(temp); } input1.close(); input2.close(); output.close(); sis.close();
- 18.2.2 OutputStream类型
决定了输出所要去往的目标:字节数组、文件或者管道
类 | 功能 |
---|---|
ByteArrayOutputStream | 在内存中创建缓冲区,所有送往“流”的数据都要放置在此缓冲区 |
FileOutputStream | 用于将信息写至文件 |
PipedOutputStream | 任何写入其中的信息都会自动作为相关PipedInputStream的输出。实现管道化概念 |
FilterOutputStream | 抽象类,作为“装饰器”的接口 |
- 18.4 Reader和Writer
InputStream和OutputStream在以面向字节形式的I/O中仍可以提供极有价值的功能,Reader和Writer则提供兼容Unicode与面向字符的I/O功能。另外:
1. Java 1.1向InputStream和OutputStream继承层次结构中添加了一些新类,所以显然这两个类是不会被取代的
2. 如何将面向字节和面向字符结合起来用?为了实现这个目的,要用到“适配器”类:InputStreamReader可以把InputStream转换成Reader,而OutputStreamWriter可以把OutputStream转换成Writer
设计Reader和Writer继承层次结构主要是为了国际化。老的I/O流继承层次结构仅支持8位字节流,并且不能很好地处理16位的Unicode字符。由于Unicode用于字符国际化(Java背身char也是16位的Unicode),所以添加Reader和Writer继承层次结构就是为了在所有的I/O操作中都支持Unicode。另外,新类库的设计使得它的操作比旧类库更快。
字符流使用:
String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); Writer out =new FileWriter(f); String str="hello"; out.write(str); out.close(); String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); char[] ch=new char[100]; Reader read=new FileReader(f); int count=read.read(ch); read.close(); System.out.println("读入的长度为:"+count); System.out.println("内容为"+new String(ch,0,count));
String fileName= "d:"+File.separator+"hello.txt"; File file=new File(fileName); Writer out=new OutputStreamWriter(new FileOutputStream(file)); out.write("hello"); out.close(); String fileName= "d:"+File.separator+"hello.txt"; File file=new File(fileName); Reader read=new InputStreamReader(new FileInputStream(file)); char[] b=new char[100]; int len=read.read(b); System.out.println(new String(b,0,len)); read.close();
- 18.8.3 标注I/O重定向
标准I/O模型中,Java提供了System.in、System.out和System.err。其中,System.out和System.err已经被包装成了PrintStream,可以直接使用,但是System.in却是InputStream,使用之前必须对其进行包装。
如果不想直接在显示器上进行输出,而是希望在文本中进行输出,那么可以对这些标准I/O进行重定向:
setIn(InputStream) setOut(PrintStream) setErr(PrintStream) public class Redirecting { public static void main(String[] args) throws IOException { PrintStream console = System.out; BufferedInputStream in = new BufferedInputStream( new FileInputStream("Redirecting.java")); PrintStream out = new PrintStream( new BufferedOutputStream( new FileOutputStream("test.out"))); System.setIn(in); System.setOut(out); System.setErr(out); BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); String s; while((s = br.readLine()) != null) System.out.println(s); out.close(); // Remember this! System.setOut(console); } } ///:~
- 18.10 新I/O(NIO)没有细看,可以参考 https://www.ibm.com/developerworks/cn/education/java/j-nio/section5.html
通道和缓冲器
- 18.10.6 内存映射文件
比较nio可以更加显著地加快速度,允许我们创建和修改那些因为太大而不能放入内存的文件。
public class LargeMappedFiles { static int length = 0x8FFFFFF; // 128 MB public static void main(String[] args) throws Exception { MappedByteBuffer out = new RandomAccessFile("test.dat", "rw").getChannel() .map(FileChannel.MapMode.READ_WRITE, 0, length); for(int i = 0; i < length; i++) out.put((byte)'x'); print("Finished writing"); for(int i = length/2; i < length/2 + 6; i++) printnb((char)out.get(i)); } } ///:~
- 18.12 对象序列化
Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象(通过ObjectOutputStream和ObjectInputStream来实现)。
对象序列化的概念加入到语言中是为了支持两种主要特性。一个是Java的远程方法调用(Remote Method Invocation,RMI),另一个对于Java Beans来说,对象的序列化也是必须的。
对象序列化特别“聪明”的一个地方是它不仅保存了对象的“全景图”,而且能追踪对象内所包含的所有引用,并保存那些对象;接着又能对对象内包含的每个这样的引用进行追踪;以此类推。
在对一个Serializable对象进行还原的过程中,没有调用任何构造器,包括默认的构造器。整个对象都是通过从InputStream中取得数据恢复而来的。
class Data implements Serializable { private int n; public Data(int n) { this.n = n; } public String toString() { return Integer.toString(n); } } public class Worm implements Serializable { private static Random rand = new Random(47); private Data[] d = { new Data(rand.nextInt(10)), new Data(rand.nextInt(10)), new Data(rand.nextInt(10)) }; private Worm next; private char c; // Value of i == number of segments public Worm(int i, char x) { print("Worm constructor: " + i); c = x; if(--i > 0) next = new Worm(i, (char)(x + 1)); } public Worm() { print("Default constructor"); } public String toString() { StringBuilder result = new StringBuilder(":"); result.append(c); result.append("("); for(Data dat : d) result.append(dat); result.append(")"); if(next != null) result.append(next); return result.toString(); } public static void main(String[] args) throws ClassNotFoundException, IOException { Worm w = new Worm(6, 'a'); print("w = " + w); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("worm.out")); out.writeObject("Worm storage\n"); out.writeObject(w); out.close(); // Also flushes output ObjectInputStream in = new ObjectInputStream( new FileInputStream("worm.out")); String s = (String)in.readObject(); Worm w2 = (Worm)in.readObject(); print(s + "w2 = " + w2); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out2 = new ObjectOutputStream(bout); out2.writeObject("Worm storage\n"); out2.writeObject(w); out2.flush(); ObjectInputStream in2 = new ObjectInputStream( new ByteArrayInputStream(bout.toByteArray())); s = (String)in2.readObject(); Worm w3 = (Worm)in2.readObject(); print(s + "w3 = " + w3); } } /* Output: Worm constructor: 6 Worm constructor: 5 Worm constructor: 4 Worm constructor: 3 Worm constructor: 2 Worm constructor: 1 w = :a(853):b(119):c(802):d(788):e(199):f(881) Worm storage w2 = :a(853):b(119):c(802):d(788):e(199):f(881) Worm storage w3 = :a(853):b(119):c(802):d(788):e(199):f(881) *///:~
- 18.12.1 寻找类
将一个对象从它的序列化状态中恢复出来,必须要保证Java虚拟机能找到相关的.class文件。否则会抛出ClassNotFoundException的异常。
- 18.12.2 序列化的控制
如果有特殊的需求,可以通过实现Externalizable接口代替实现Serializable接口,来对序列化过程进行控制。
class Blip1 implements Externalizable { public Blip1() { print("Blip1 Constructor"); } public void writeExternal(ObjectOutput out) throws IOException { print("Blip1.writeExternal"); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { print("Blip1.readExternal"); } } class Blip2 implements Externalizable { Blip2() { print("Blip2 Constructor"); } public void writeExternal(ObjectOutput out) throws IOException { print("Blip2.writeExternal"); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { print("Blip2.readExternal"); } } public class Blips { public static void main(String[] args) throws IOException, ClassNotFoundException { print("Constructing objects:"); Blip1 b1 = new Blip1(); Blip2 b2 = new Blip2(); ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("Blips.out")); print("Saving objects:"); o.writeObject(b1); o.writeObject(b2); o.close(); // Now get them back: ObjectInputStream in = new ObjectInputStream( new FileInputStream("Blips.out")); print("Recovering b1:"); b1 = (Blip1)in.readObject(); // OOPS! Throws an exception: //! print("Recovering b2:"); //! b2 = (Blip2)in.readObject(); } } /* Output: Constructing objects: Blip1 Constructor Blip2 Constructor Saving objects: Blip1.writeExternal Blip2.writeExternal Recovering b1: Blip1 Constructor Blip1.readExternal *///:~
在恢复b2的时候报错,因为Blip2的构造器不是public的。
对于Serializable对象,对象完全以它存储的二进制位为基础来构造,而不调用构造器。而对于一个Externalizable对象,所有普通的默认构造器都会被调用(包括在字段定义时的初始化),然后调用readExternal()。
如何完整保存和恢复一个Externalizable对象:
public class Blip3 implements Externalizable { private int i; private String s; // No initialization public Blip3() { print("Blip3 Constructor"); // s, i not initialized } public Blip3(String x, int a) { print("Blip3(String x, int a)"); s = x; i = a; // s & i initialized only in non-default constructor. } public String toString() { return s + i; } public void writeExternal(ObjectOutput out) throws IOException { print("Blip3.writeExternal"); // You must do this: out.writeObject(s); out.writeInt(i); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { print("Blip3.readExternal"); // You must do this: s = (String)in.readObject(); i = in.readInt(); } public static void main(String[] args) throws IOException, ClassNotFoundException { print("Constructing objects:"); Blip3 b3 = new Blip3("A String ", 47); print(b3); ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("Blip3.out")); print("Saving object:"); o.writeObject(b3); o.close(); // Now get it back: ObjectInputStream in = new ObjectInputStream( new FileInputStream("Blip3.out")); print("Recovering b3:"); b3 = (Blip3)in.readObject(); print(b3); } } /* Output: Constructing objects: Blip3(String x, int a) A String 47 Saving object: Blip3.writeExternal Recovering b3: Blip3 Constructor Blip3.readExternal A String 47 *///:~
如果注释掉跟随于“You must do this”后面的两行代码,那么还原后,s是null,而i是0.
transient关键字
如果我们操作的是一个Serializable对象,那么所有序列化都会自动进行。为了能够进行控制,可以用transient关键字指定字段关闭序列化。例如保存某个特定的登录会话信息,但是不包括密码
public class Logon implements Serializable { private Date date = new Date(); private String username; private transient String password; public Logon(String name, String pwd) { username = name; password = pwd; } public String toString() { return "logon info: \n username: " + username + "\n date: " + date + "\n password: " + password; } public static void main(String[] args) throws Exception { Logon a = new Logon("Hulk", "myLittlePony"); print("logon a = " + a); ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("Logon.out")); o.writeObject(a); o.close(); TimeUnit.SECONDS.sleep(1); // Delay // Now get them back: ObjectInputStream in = new ObjectInputStream( new FileInputStream("Logon.out")); print("Recovering object at " + new Date()); a = (Logon)in.readObject(); print("logon a = " + a); } } /* Output: (Sample) logon a = logon info: username: Hulk date: Sat Nov 19 15:03:26 MST 2005 password: myLittlePony Recovering object at Sat Nov 19 15:03:28 MST 2005 logon a = logon info: username: Hulk date: Sat Nov 19 15:03:26 MST 2005 password: null *///:~
由于Externalizable对象在默认情况下不保存它们的任何字段,所以transien关键字只能和Serializable对象一起使用。
Externalizable的替代方法
实现Serializable接口,并添加名为writeObject()和readObject()的方法。(是添加,不是覆盖或者实现,因为这两个方法不是接口中定义的,而且是私有方法)
调用defaultWriteObject()和defaultReadObject()可以调用默认的写和读:
public class SerialCtl implements Serializable { private String a; private transient String b; public SerialCtl(String aa, String bb) { a = "Not Transient: " + aa; b = "Transient: " + bb; } public String toString() { return a + "\n" + b; } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeObject(b); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); b = (String)stream.readObject(); } public static void main(String[] args) throws IOException, ClassNotFoundException { SerialCtl sc = new SerialCtl("Test1", "Test2"); System.out.println("Before:\n" + sc); ByteArrayOutputStream buf= new ByteArrayOutputStream(); ObjectOutputStream o = new ObjectOutputStream(buf); o.writeObject(sc); // Now get it back: ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(buf.toByteArray())); SerialCtl sc2 = (SerialCtl)in.readObject(); System.out.println("After:\n" + sc2); } } /* Output: Before: Not Transient: Test1 Transient: Test2 After: Not Transient: Test1 Transient: Test2 *///:~
o.writeObject(sc);会检查sc判断它是否拥有自己的writeObject()方法,如果有,那么就会直接使用它。同理对于readObject()。
- 18.12.3 使用“持久性”
Serializable对象的序列化和反序列化可以实现对象的“深度复制”(即复制整个对象网,而不是仅仅是基本对象及其引用):
class House implements Serializable {} class Animal implements Serializable { private String name; private House preferredHouse; Animal(String nm, House h) { name = nm; preferredHouse = h; } public String toString() { return name + "[" + super.toString() + "], " + preferredHouse + "\n"; } } public class MyWorld { public static void main(String[] args) throws IOException, ClassNotFoundException { House house = new House(); List<Animal> animals = new ArrayList<Animal>(); animals.add(new Animal("Bosco the dog", house)); animals.add(new Animal("Ralph the hamster", house)); animals.add(new Animal("Molly the cat", house)); print("animals: " + animals); ByteArrayOutputStream buf1 = new ByteArrayOutputStream(); ObjectOutputStream o1 = new ObjectOutputStream(buf1); o1.writeObject(animals); o1.writeObject(animals); // Write a 2nd set // Write to a different stream: ByteArrayOutputStream buf2 = new ByteArrayOutputStream(); ObjectOutputStream o2 = new ObjectOutputStream(buf2); o2.writeObject(animals); // Now get them back: ObjectInputStream in1 = new ObjectInputStream( new ByteArrayInputStream(buf1.toByteArray())); ObjectInputStream in2 = new ObjectInputStream( new ByteArrayInputStream(buf2.toByteArray())); List animals1 = (List)in1.readObject(), animals2 = (List)in1.readObject(), animals3 = (List)in2.readObject(); print("animals1: " + animals1); print("animals2: " + animals2); print("animals3: " + animals3); } } /* Output: (Sample) animals: [Bosco the dog[Animal@addbf1], House@42e816 , Ralph the hamster[Animal@9304b1], House@42e816 , Molly the cat[Animal@190d11], House@42e816 ] animals1: [Bosco the dog[Animal@de6f34], House@156ee8e , Ralph the hamster[Animal@47b480], House@156ee8e , Molly the cat[Animal@19b49e6], House@156ee8e ] animals2: [Bosco the dog[Animal@de6f34], House@156ee8e , Ralph the hamster[Animal@47b480], House@156ee8e , Molly the cat[Animal@19b49e6], House@156ee8e ] animals3: [Bosco the dog[Animal@10d448], House@e0e1c6 , Ralph the hamster[Animal@6ca1c], House@e0e1c6 , Molly the cat[Animal@1bf216a], House@e0e1c6 ] *///:~
只要将任何对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网。
静态变量(static字段修饰的)不会序列化,需要自己动手去实现。
abstract class Shape implements Serializable { public static final int RED = 1, BLUE = 2, GREEN = 3; private int xPos, yPos, dimension; private static Random rand = new Random(47); private static int counter = 0; public abstract void setColor(int newColor); public abstract int getColor(); public Shape(int xVal, int yVal, int dim) { xPos = xVal; yPos = yVal; dimension = dim; } public String toString() { return getClass() + "color[" + getColor() + "] xPos[" + xPos + "] yPos[" + yPos + "] dim[" + dimension + "]\n"; } public static Shape randomFactory() { int xVal = rand.nextInt(100); int yVal = rand.nextInt(100); int dim = rand.nextInt(100); switch(counter++ % 3) { default: case 0: return new Circle(xVal, yVal, dim); case 1: return new Square(xVal, yVal, dim); case 2: return new Line(xVal, yVal, dim); } } } class Circle extends Shape { private static int color = RED; public Circle(int xVal, int yVal, int dim) { super(xVal, yVal, dim); } public void setColor(int newColor) { color = newColor; } public int getColor() { return color; } } class Square extends Shape { private static int color; public Square(int xVal, int yVal, int dim) { super(xVal, yVal, dim); color = RED; } public void setColor(int newColor) { color = newColor; } public int getColor() { return color; } } class Line extends Shape { private static int color = RED; public static void serializeStaticState(ObjectOutputStream os) throws IOException { os.writeInt(color); } public static void deserializeStaticState(ObjectInputStream os) throws IOException { color = os.readInt(); } public Line(int xVal, int yVal, int dim) { super(xVal, yVal, dim); } public void setColor(int newColor) { color = newColor; } public int getColor() { return color; } } public class StoreCADState { public static void main(String[] args) throws Exception { List<Class<? extends Shape>> shapeTypes = new ArrayList<Class<? extends Shape>>(); // Add references to the class objects: shapeTypes.add(Circle.class); shapeTypes.add(Square.class); shapeTypes.add(Line.class); List<Shape> shapes = new ArrayList<Shape>(); // Make some shapes: for(int i = 0; i < 10; i++) shapes.add(Shape.randomFactory()); // Set all the static colors to GREEN: for(int i = 0; i < 10; i++) ((Shape)shapes.get(i)).setColor(Shape.GREEN); // Save the state vector: ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("CADState.out")); out.writeObject(shapeTypes); Line.serializeStaticState(out); out.writeObject(shapes); // Display the shapes: System.out.println(shapes); } } /* Output: [class Circlecolor[3] xPos[58] yPos[55] dim[93] , class Squarecolor[3] xPos[61] yPos[61] dim[29] , class Linecolor[3] xPos[68] yPos[0] dim[22] , class Circlecolor[3] xPos[7] yPos[88] dim[28] , class Squarecolor[3] xPos[51] yPos[89] dim[9] , class Linecolor[3] xPos[78] yPos[98] dim[61] , class Circlecolor[3] xPos[20] yPos[58] dim[16] , class Squarecolor[3] xPos[40] yPos[11] dim[22] , class Linecolor[3] xPos[4] yPos[83] dim[6] , class Circlecolor[3] xPos[75] yPos[10] dim[42] ] *///:~
Line.serializeStaticState(out);就是自己实现static值。
- 18.13 XML
没有细看,自己网上找了下DOM与SAX的区别:
In SAX, events are triggered when the XML is being parsed. When the parser is parsing the XML, and encounters a tag starting (e.g. ), then it triggers the tagStarted event (actual name of event might differ). Similarly when the end of the tag is met while parsing (), it triggers tagEnded. Using a SAX parser implies you need to handle these events and make sense of the data returned with each event.
In DOM, there are no events triggered while parsing. The entire XML is parsed and a DOM tree (of the nodes in the XML) is generated and returned. Once parsed, the user can navigate the tree to access the various data previously embedded in the various nodes in the XML.
In general, DOM is easier to use but has an overhead of parsing the entire XML before you can start using it.
SAX是事件驱动的,解析效率高,不将整个文档载入内存中,占用内存少,不过不能写入XML。
DOM是将整个文档树在内存中,便于操作,支持删除、修改、重新排序等,但是将整个文档放入内存,浪费时间和空间
- 18.14 Preferences
它只能用于小的、受限的数据集合–我们只能存储基本类型和字符串,并且每个字符串的存储长度不能超过8K。
public class PreferencesDemo { public static void main(String[] args) throws Exception { Preferences prefs = Preferences .userNodeForPackage(PreferencesDemo.class); prefs.put("Location", "Oz"); prefs.put("Footwear", "Ruby Slippers"); prefs.putInt("Companions", 4); prefs.putBoolean("Are there witches?", true); int usageCount = prefs.getInt("UsageCount", 0); usageCount++; prefs.putInt("UsageCount", usageCount); for(String key : prefs.keys()) print(key + ": "+ prefs.get(key, null)); // You must always provide a default value: print("How many companions does Dorothy have? " + prefs.getInt("Companions", 0)); } } /* Output: (Sample) Location: Oz Footwear: Ruby Slippers Companions: 4 Are there witches?: true UsageCount: 53 How many companions does Dorothy have? 4 *///:~
Preferences存储的数据在哪里呢?Windows是存在注册表中的
http://support.inqscribe.com/knowledgebase/articles/14405-how-do-i-find-my-preferences-file
相关文章