该课内容: Java I/O操作,字节流InputStream和OutputStream,字符流Reader和Writer,Java I/O库的设计原则,字符集的编码,RandomAccessFile类,管道流,对象的序列化.
File类.
- 一个File类的对象,表示了磁盘上的文件或目录.
- File类提供了与平台无关的方法来对磁盘上的文件或目录进行操作.
EX. 文件操作
package test; import java.io.*; class Test { // 由于文件操作很多地方都有异常处理机制.因此做如下简化操作 public static void main(String[] args) throws Exception{ /* File f = new File("123.txt"); // 相对路径 File f = new File("I:\\Java\\test\\123.txt"); // 绝对路径 f.createNewFile(); // 创建文件. f.mkdir(); // 创建目录 f.delete(); // 删除文件 f.deleteOnExit(); // 程序退出时删除文件 */ // 由于windows下分隔符是/.而linux下是\.此时可用分隔符常量. /* File fDir = new File(File.separator); String strFile = "Java" + File.separator + "test" + File.separator + "123.txt"; File f = new File(fDir , strFile); f.createNewFile(); */ // 创建临时文件 for (int i = 0; i < 5; ++i){ File f = File.createTempFile("test", ".tmp"); f.deleteOnExit(); } // 遍历文件夹下的文件与文件夹 File fDir = new File(File.separator); String strFile = "Java" + File.separator + "test" ; File f = new File(fDir, strFile); // 实现过滤器接口.对文件名进行过滤 String[] names = f.list(new FilenameFilter(){ public boolean accept(File dir, String name){ return name.indexOf(".txt") != -1; } }); for (int i = 0; i < names.length; ++i){ System.out.println(names[i]); } } }
流式I/O.
- 流(Stream)是字节的源或目的.
- 两种基本的流是.输入流(Input Stream)和输出流(Output Stream).可从中读出一系列字节的对象称为输入流.而能向其中写入一系列字节的对象称为输出流.
流可以分为:
- 节点流.从特定的地方读写的流类,例如:磁盘或一块内存区域。
- 过滤流.使用节点流作为输入或输出.过滤流是使用一个已经存在的输入流或输出流连接创建的.
EX. FileInputStream & FileOutputStream
package test; import java.io.*; class Test { public static void main(String[] args) throws Exception{ // FileInputStream\FileOutputStream // 向文件中写入数据 FileOutputStream fos = new FileOutputStream("123.txt"); fos.write("come on".getBytes()); fos.close(); // 从文件中读取数据 FileInputStream fis = new FileInputStream("123.txt"); byte[] buf = new byte[100]; int len = fis.read(buf); System.out.println(new String(buf, 0, len)); fis.close(); } }
EX. BufferedInputStream & FileOutputStream
package test; import java.io.*; class Test { public static void main(String[] args) throws Exception{ // 向文件中写入数据 FileOutputStream fos = new FileOutputStream("123.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write("come on".getBytes()); // 将数据写入缓冲区 bos.flush(); // 将缓冲区写入硬盘 bos.close(); // 只需要关闭bos即可 // 从文件中读取数据 FileInputStream fis = new FileInputStream("123.txt"); BufferedInputStream bis = new BufferedInputStream(fis); byte[] buf = new byte[100]; int len = bis.read(buf); bis.close(); System.out.println(new String(buf, 0, len)); bis.close(); } }
EX. DataInputStream & DataOutputStream
package test; import java.io.*; class Test { public static void main(String[] args) throws Exception{ // 向文件中写入数据 FileOutputStream fos = new FileOutputStream("123.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); DataOutputStream dos = new DataOutputStream(bos); byte b = 3; int i = 78; char ch = ‘a‘; float f = 4.5f; dos.writeByte(b); dos.writeInt(i); dos.writeChar(ch); dos.writeFloat(f); dos.close(); // 从文件中读取数据 FileInputStream fis = new FileInputStream("123.txt"); BufferedInputStream bis = new BufferedInputStream(fis); DataInputStream dis = new DataInputStream(bis); System.out.println(dis.readByte()); System.out.println(dis.readInt()); System.out.println(dis.readChar()); System.out.println(dis.readFloat()); bis.close(); } }
EX. PipedInputStream & PipedOutputStream. 线程间通信
package test; import java.io.*; class Test { public static void main(String[] args) throws Exception{ PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(); try { pos.connect(pis); new Producer(pos).start(); new Consumer(pis).start(); } catch (Exception ex){ ex.printStackTrace(); } } } class Producer extends Thread{ private PipedOutputStream pos; public Producer(PipedOutputStream pos){ this.pos = pos; } public void run(){ try{ pos.write("hello world.".getBytes()); pos.close(); } catch (Exception ex){ ex.printStackTrace(); } } } class Consumer extends Thread{ private PipedInputStream pis; public Consumer(PipedInputStream pis){ this.pis = pis; } public void run(){ try{ byte[] buf = new byte[100]; int len = pis.read(buf); System.out.println(new String(buf, 0,len)); pis.close(); } catch (Exception ex){ ex.printStackTrace(); } } }
流式I/O的链接.
Reader和Writer.
- Java程序语言使用Unicode来表示字符串和字符.
- Reader和Writer这两个抽象类主要用来读写字符流.
EX. BufferedWriter & BufferedReader. 线程间通信
package test; import java.io.*; class Test { public static void main(String[] args) throws Exception{ // 写入字符流 FileOutputStream fos = new FileOutputStream("123.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter bw = new BufferedWriter(osw); bw.write("come on"); bw.close(); // 读取字符流 FileInputStream fis = new FileInputStream("123.txt"); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr); System.out.println(br.readLine()); br.close(); InputStreamReader isr2 = new InputStreamReader(System.in); BufferedReader br2 = new BufferedReader(isr2); String strLine; while ((strLine = br2.readLine() )!= null){ System.out.println(strLine); } br.close(); } }
字符集的编码.
- ASCII(American Standard Code for Information Interchange,美国信息互换标准代码),是基于常用的英文字符的一套电脑编码系统。我们知道英文中经常使用的字符、数字符号被计算机处理时都是以二进制码的形式出现的。这种二进制码的集合就是所谓的ASCII码。每一个ASCII码与一个8位(bit)二进制数对应。其最高位是0,相应的十进制数是0-127。如,数字“0”的编码用十进制数表示就是48。另有128个扩展的ASCII码,最高位都是1,由一些制表符和其它符号组成。ASCII是现今最通用的单字节编码系统。
- GB2312:GB2312码是*国家汉字信息交换用编码,全称《信息交换用汉字编码字符集-基本集》。主要用于给每一个中文字符指定相应的数字,也就是进行编码。一个中文字符用两个字节的数字来表示,为了和ASCII码有所区别,将中文字符每一个字节的最高位置都用1来表示。
- GBK:为了对更多的字符进行编码,国家又发布了新的编码系统GBK(GBK的K是“扩展”的汉语拼音第一个字母)。在新的编码系统里,除了完全兼容GB2312 外,还对繁体中文、一些不常用的汉字和许多符号进行了编码。
- ISO-8859-1:是西方国家所使用的字符编码集,是一种单字节的字符集 ,而英文实际上只用了其中数字小于128的部分。
- Unicode:这是一种通用的字符集,对所有语言的文字进行了统一编码,对每一个字符都用2个字节来表示,对于英文字符采取前面加“0”字节的策略实现等长兼容。如 “a” 的ASCII码为0x61,UNICODE就为0x00,0x61。
- UTF-8:Eight-bit UCS Transformation Format,(UCS,Universal Character Set,通用字符集,UCS 是所有其他字符集标准的一个超集)。一个7位的ASCII码值,对应的UTF码是一个字节。如果字符是0x0000,或在0x0080与0x007f之间,对应的UTF码是两个字节,如果字符在0x0800与0xffff之间,对应的UTF码是三个字节。
RandomAccessFile.
- RandomAccessFile类同时实现了DataInput和DataOutput接口,提供了对文件随机存取的功能,利用这个类可以在文件的任何位置读取或写入数据。
- RandomAccessFile类提供了一个文件指针,用来标志要进行读写操作的下一数据的位置。
EX. RandomAccessFile示例
package test; import java.io.*; class Test { public static void main(String[] args) throws Exception{ Student s1 = new Student(1, "a", 90); Student s2 = new Student(2, "b", 90.5); Student s3 = new Student(3, "c", 89.5); RandomAccessFile raf = new RandomAccessFile("Student.txt", "rw"); s1.writeStudent(raf); s2.writeStudent(raf); s3.writeStudent(raf); Student s = new Student(); raf.seek(0); // 将文件指针移至文件起始位置 for (long i = 0; i < raf.length(); i = raf.getFilePointer()){ s.readStudent(raf); System.out.println(s); } raf.close(); } } class Student{ int id; String name; double score; public Student(){} public Student(int id, String name, double score){ this.id = id; this.name = name; this.score = score; } // 写入数据 public void writeStudent(RandomAccessFile raf) throws IOException{ raf.writeInt(id); raf.writeUTF(name); raf.writeDouble(score); } // 读取数据 public void readStudent(RandomAccessFile raf) throws IOException{ id = raf.readInt(); name = raf.readUTF(); score = raf.readDouble(); } public String toString(){ return "id:" + id + ", name:" + name + ", score:" + score; } }
对象序列化.
- 将对象转换为字节流保存起来,并在日后还原这个对象,这种机制叫做对象序列化。
- 将一个对象保存到永久存储设备上称为持续性。
- 一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口。
- 当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
- 如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
- 如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
EX.序列化示例
package test; import java.io.*; class Test { public static void main(String[] args) throws Exception{ Employee e1 = new Employee("a", 23, 3000); Employee e2 = new Employee("b", 24, 4000); Employee e3 = new Employee("c", 25, 5000); FileOutputStream fos = new FileOutputStream("employee.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(e1); oos.writeObject(e2); oos.writeObject(e3); oos.close(); // 反序列化.(不调用对象的任何构造方法) FileInputStream fis = new FileInputStream("employee.txt"); ObjectInputStream ois = new ObjectInputStream(fis); for (int i = 0; i < 3; ++i) System.out.println(ois.readObject()); } } class Employee implements Serializable{ String name; int age; double salary; public Employee(String name, int age, double salary){ this.name = name; this.age = age; this.salary = salary; } public String toString(){ return "name:" + name + ", age:" + age + ", salary:" + salary; } /* 自定义序列化 private void writeObject(ObjectOutputStream oos) throws IOException{} private void readObject(ObjectInputStream oos) throws IOException{} */ }