注:本文为作者学习总结,如有错误请见谅与及批评指出
1.输入输出流
计算机存储文件在物理上都是以二进制的形式存储,根据逻辑上的不同一般分为以下两种:
文本文件:每个字符对应一个ASCII(Unicode)码,用二进制形式写入磁盘,即文本与二进制之间是以Unicode(ASCII)等常见编码方式翻译。文本编辑器能够打开文本文件。
二进制文件:磁盘同样以二进制保存,但是翻译不再是Unicode(ASCII)等常见编码方式,不同程序自己定义。文本编辑器打开的是乱码文件。
文本文件用字符流(基于字符char)进行读写,二进制文件用字节流(基于字节byte)进行读写。图1为常见的字节流各个类,图2为常见的字符流各个类,图3为输入输出流中常用的一些接口。
图1 常见字节流层次结构
图2 常见字符流层次结构
图3 输入输出流常见接口
2.文本文件读写
Reader(抽象类)是字符输入流的父类,Writer(抽象类)是字符输出流的父类。字符流是以字符(char)为单位读写数据的,一次处理一个unicode,且其底层仍然是基本的字节流。通俗的说,写入时采用某种编码方式把字符转换成二进制存入磁盘中,读取时按照同样的编码方式把二进制读取出来并且转换成字符。因此,字符流只能操作文本文件。
2.0 字符转换流原理
InputStreamReader:可以设置字符集,按照此编码方式将字节转换为字符并且读取。构造函数:InputStreamReader(InputStream in,String charsetName)和InputStreamReader(InputStream in)--系统默认字符集
OutputStreamWriter:可以设置字符集,按照此编码方式将字符转换为字节并且写出。构造函数:OutputStreamWriter(OutputStream out,String charsetName)和OutputStreamWriter(OutputStream out)--系统默认字符集
2.1 文本输出(PrintWriter)
常见构造器:
PrintWriter(File file)PrintWriter(String filename)PrintWriter(File file,String encoding)PrintWriter(String filename,String encoding)PrintWriter(Writer writer)PrintWriter(Writer writer,boolean autoFlush)PrintWriter(OutputStream out)PrintWriter(OutputStream out,boolean autoFlush)
常见方法:
void print(Object obj) //打印obj的toString后的字符串void print(String s)void println(String s)void print(char[] s)void print(char c)void print(int i)void print(long l)void print(float f)void print(double d)void print(boolean b) //以文本格式打印void print(String format,Object... args) //按指定格式打印字符串
例子:
PrintWriter out=new PrintWriter("C:\\Users\\Administrator\\Desktop\\raf.dat","UTF-8");PrintWriter out=new PrintWriter(new OutputStreamWriter(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\raf.dat"),"UTF-8"),true);
2.2 文本读入
(1)Scanner类(Scanner(InputStream in,String charsetName))
try(Scanner in=new Scanner(new FileInputStream("C:\\Users\\Administrator\\Desktop\\raf.dat"),"UTF-8")) { while(in.hasNextLine()){ System.out.println(in.nextLine()); }}
(2)短小文本读入一个字符串中
String content=new String(Files.readAllBytes(Paths.get("C:\\Users\\Administrator\\Desktop\\raf.dat")),"UTF-8");
(3)短小文本一行一行地读
Listlines=Files.readAllLines(Paths.get("C:\\Users\\Administrator\\Desktop\\raf.dat"),StandardCharsets.UTF_8);for(String s:lines){ System.out.println(s);}
(4)大文件将行惰性处理成一个Stream<String>对象(JDK1.8)
try(Streamlines=Files.lines(Paths.get("C:\\Users\\Administrator\\Desktop\\raf.dat"),StandardCharsets.UTF_8)){ ... }
(5)BufferedReader类
FileInputStream fin=new FileInputStream("C:\\Users\\Administrator\\Desktop\\raf.dat");InputStreamReader isr=new InputStreamReader(fin,StandardCharsets.UTF_8);try(BufferedReader in=new BufferedReader(isr);){ String line; while((line=in.readLine())!=null){ System.out.println(line); }}
3.二进制文件读写
3.0 DataInput和DataOutput接口
DataInput接口:用于读取二进制格式的数字(组)、字符、boolean和字符串。
常用方法:writeByte、writeInt、writeShort、writeLong、writeFloat、writeDouble、writeChar、writeBoolean、writeChars、writeUTF(只在写出用于java虚拟机的字符串)
DataOutput接口:用于以二进制格式写数字(组)、字符、boolean和字符串。
常用方法:readByte、readInt、readShort、readLong、readFloat、readDouble、readChar、readBoolean、readUTF、skipBytes(int n)
3.1 DataInputStream和DataOutputStream实现读写
try(DataOutputStream out=new DataOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\raf.dat"))){ out.writeInt(222); out.writeDouble(222.22); out.writeUTF("郭无");}try(DataInputStream in=new DataInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\raf.dat"))){ System.out.println(in.readInt()+","+in.readDouble()+","+in.readUTF());}
3.2 RandomAccessFile实现读写
RandomAccessFile同时实现了DataInput和DataOutput接口,可以使用构造器第二个参数r/rw指定打开方式。有一个表示下一个将被读入或者写出的字节所处位置的文件指针。
常用构造器:
RandomAccessFile(File file,String mode)RandomAccessFile(String filename,String mode) //mode:r rw
额外常用方法:
seek(Long long):把文件指针设置到任意字节位置(0到文件字节长度)getFilePointer:返回文件指针当前位置length()文件字节总数 skipBytes(int n):跳过n个字节
例子:
try(RandomAccessFile raf=new RandomAccessFile("C:\\Users\\Administrator\\Desktop\\raf.dat","rw")){ raf.writeInt(123); raf.writeDouble(123.56); raf.writeUTF("郭文景"); }/try(RandomAccessFile raf=new RandomAccessFile("C:\\Users\\Administrator\\Desktop\\raf.dat","rw")){ System.out.println(raf.readInt()+","+raf.readDouble()+","+raf.readUTF()); }
3.3 ZIP文档
java操作zip文档主要涉及以下四个类:ZipInputStream、ZipOutStream、ZipEntry、ZipFile
(1)写入zip文件
FileOutputStream fOutputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\gwj1.zip");ZipOutputStream zoutput = new ZipOutputStream(fOutputStream);String line="gwj";for(int i=0;i<3;i++){ byte[] bytes=(line+i).getBytes(); ZipEntry zEntry = new ZipEntry("no"+i+".txt"); zoutput.putNextEntry(zEntry); zoutput.write(bytes); zoutput.closeEntry();}zoutput.close();
(2)读取zip文件(ZipFile和ZipInputStream都行)
ZipFile zipfile=new ZipFile("C:\\Users\\Administrator\\Desktop\\gwj1.zip");ZipEntry entry;Enumeration e = zipfile.entries();while(e.hasMoreElements()){entry = (ZipEntry) e.nextElement();System.out.println("-------"+entry.getName()+"-------");InputStreamReader isr=new InputStreamReader(zipfile.getInputStream(entry),StandardCharsets.UTF_8);try(BufferedReader in=new BufferedReader(isr);){String line;while((line=in.readLine())!=null){ System.out.println(line); } } }
3.4 对象系列化
(1)对象系列化使用
Employee harry = new Employee("Harry Hacker", 50000, 1989, 10, 1);Manager carl = new Manager("Carl Cracker", 80000, 1987, 12, 15);carl.setSecretary(harry);Manager tony = new Manager("Tony Tester", 40000, 1990, 3, 15);tony.setSecretary(harry);Employee[] staff = new Employee[3];staff[0] = carl;staff[1] = harry;staff[2] = tony;String name="郭文景";// save all employee records to the file employee.dat try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\employee.dat"))) { out.writeObject(staff); out.writeUTF(name);}try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\employee.dat"))){ Employee[] newStaff = (Employee[]) in.readObject(); newStaff[1].raiseSalary(10); for (Employee e : newStaff) System.out.println(e); System.out.println(in.readUTF());}
注:Employee需要实现Serializable接口。Employee implements Serializable
(2)对象系列化原理
- 对象系列化的文件格式