IO流_字符流、序列流、对象输出流(Reader,Writer, SequenceInputStream ,ObjectOutputStream)——Java基础

本文参考自: 原文地址

 1.  字符流:字节流 + 编码表

在写入一个字符时,Java虚拟机会将字符转为文件指定的编码(默认是系统默认编码),在读取字符时,再将文件指定的编码转化为字符。 

常见的码表如下:
ASCII: 美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1: 拉丁码表。欧洲码表,用一个字节的8位表示。。
GB2312: 英文占一个字节,中文占两个字节. 中国的中文编码表。
GBK: 中国的中文编码表升级版,两个字节包含了英文字符和扩展的中文
Unicode:  国际标准码规范,融合了多种文字。所有文字都用两个字节来表示, Java语言使用的就是unicode

UTF-8: 最多用三个字节来表示一个字符。

eg:     "中国".getBytes() 即可得到字符串对应的字节数组是[-42, -48, -71, -6]

2.  Reader
int read():  读取一个字符。返回的是读到的那个字符。如果读到流的末尾,返回-1.
int read(char[]):将读到的字符存入指定的数组中,返回的是读到的字符个数。如果读到流的末尾,返回-1.

字节流 与 字符流  读取文件内容  对比
public class IoTest1_Reader {

	public static void main(String[] args) throws Exception {
		String path = "c:/a.txt";
		// readFileByInputStream(path);
		readFileByReader(path);
	}
/**使用  字节流  读取文件内容 */
	public static void readFileByInputStream(String path) throws Exception {
		InputStream in = new FileInputStream(path);
		int len = 0;
		while ((len = in.read()) != -1) {
			System.out.print((char) len);
		}
		in.close();
	}
/** 使用  字符流  读取文件内容 */
	public static void readFileByReader(String path) throws Exception {
		Reader reader = new FileReader(path);
		int len = 0;
		while ((len = reader.read()) != -1) {
			System.out.print((char) len);
		}
		reader.close();
	}
}
3.  Writer

Writer中的常见的方法:

write(ch): 将一个字符写入到流中。

write(char[]): 将一个字符数组写入到流中。

write(String): 将一个字符串写入到流中。

flush():刷新流,将流中的数据刷新到目的地中,流还存在。close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭。

 *    FileWrite 注意的事项:
 *       1.  内部是维护一个1024个字符数组的,  flush(),close()方法
 *       2.  使用 FileWrite 时,没有目标文件,会自动创建
 *       3.  目标文件已经存在,会默认清空文件中的数据。如果需要在原来的基础上,需要使用new FileWriter(file,true)方法。

File file = new File("J:/a.txt");
FileWriter fileWriter = new FileWriter(file, true);
String data = "女神经付祖贤女侠";
fileWriter.write(data);   // 字符流具备解码的功能
4.  字符流的缓冲区:  BufferedReader 类
    Reader有一个子类BufferedReader类,该类提供了方法readLine()方法,具备 一次读取一个文本行的功能。
注意:  缓冲的存在是为了增强流的功能而存在,所以在建立缓冲区对象时,要先有流对象存在.  缓冲区的出现提高了对流的操作效率。原理:其实就是将数组进行封装。
File srcFile = new File("c:\\linux大纲.txt");
FileReader fr = new FileReader(srcFile); 
BufferedReader br = new BufferedReader(fr); 
例子: 使用字符流缓冲区拷贝文本文件.
public class Demo7 {
	public static void main(String[] args) throws IOException {		
		File srcFile = new File("c:\\linux大纲.txt");  // 关联源文件	
		File destFile = new File("d:\\linux大纲.txt");   // 关联目标文件		
		copyFile(srcFile, destFile);    // 实现拷贝
	}
	private static void copyFile(File srcFile, File destFile) throws IOException {
		
		FileReader fr = new FileReader(srcFile);    // 创建字符输入流	
		FileWriter fw = new FileWriter(destFile);   // 创建字符输出流		
		BufferedReader br = new BufferedReader(fr);   // 字符输入流的缓冲区	
		BufferedWriter bw = new BufferedWriter(fw);   // 字符输出流的缓冲区

		String line = null;	
		while ((line = br.readLine()) != null) {   	// 一次读取一行		
			bw.write(line);  // 一次写出一行.		
			bw.flush();   // 刷新缓冲
			bw.newLine();   // 进行换行,由于readLine方法默认没有换行.需要手动换行
		}		
		br.close();
		bw.close();
	}
}
5.  SequenceInputStream 序列流
 *    构造方法:
 *      SequenceInputStream(Enumeration<? extends InputStream> e) 
              通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。     
        SequenceInputStream(InputStream s1, InputStream s2) 
          通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。

例子:  将a.txt 和 b.txt文件的内容合并  
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;

public class test_1 {	
	public static void main(String[] args) throws IOException   {				
	//	merge1();
	//	merge2();
		merge3();
	}
//  合并方法一	
	public static void merge1() throws IOException {
		File file1 = new File("J:/a.txt");
		File file2 = new File("J:/b.txt");
		File outfile = new File("J:/c.txt");
		FileInputStream fileInputStream1 = new FileInputStream(file1);
	        FileInputStream fileInputStream2 = new FileInputStream(file2);	    
		FileOutputStream fileOutputStream = new FileOutputStream(outfile);

		ArrayList<FileInputStream> list = new ArrayList<FileInputStream>();		
		list.add(fileInputStream1);
		list.add(fileInputStream2);		
		byte[] buf = new byte[100];
		int length = 0;
		
		for(int i=0; i<list.size(); i++) {
			FileInputStream fileInputStream = list.get(i);
			while((length = fileInputStream.read(buf))!=-1) {
				fileOutputStream.write(buf,0,length);								
			}				
			fileInputStream.close();					
		}
		fileOutputStream.close();	
	}
 // 合并方法二:  两个文件合并,使用序列化
	public static void merge2() throws IOException {
		File file1 = new File("J:/a.txt");
		File file2 = new File("J:/b.txt");
		File outfile = new File("J:/c.txt");
		FileInputStream fileInputStream1 = new FileInputStream(file1);
	        FileInputStream fileInputStream2 = new FileInputStream(file2);
	        SequenceInputStream inputStream = new SequenceInputStream(fileInputStream1, fileInputStream2);    
		FileOutputStream fileOutputStream = new FileOutputStream(outfile);
		
		byte[] buf = new byte[1024];
		int length = 0;
		while((length = inputStream.read(buf))!=-1) {			
			fileOutputStream.write(buf,0,length);			
		}		
		inputStream.close();
		fileOutputStream.close();		
	}
//合并方法三: 多个文件读写 ,采用vector的迭代器
	public static void merge3() throws IOException {
		File file1 = new File("J:/a.txt");
		File file2 = new File("J:/b.txt");
		File file3 = new File("J:/c.txt");
		File file4 = new File("J:/d.txt");
		File outfile = new File("J:/e.txt");
	    FileInputStream fileInputStream1 = new FileInputStream(file1);
	    FileInputStream fileInputStream2 = new FileInputStream(file2);
	    FileInputStream fileInputStream3 = new FileInputStream(file3);
	    FileInputStream fileInputStream4 = new FileInputStream(file4);
	    FileOutputStream fileOutputStream = new FileOutputStream(outfile);
	    
	    Vector<FileInputStream> vector = new Vector<FileInputStream>();
	    vector.add(fileInputStream1);
	    vector.add(fileInputStream2);
	    vector.add(fileInputStream3);
	    vector.add(fileInputStream4);
	 
	    Enumeration<FileInputStream> enumeration = vector.elements();     //  创建迭代器    
	    SequenceInputStream sequenceInputStream = new SequenceInputStream(enumeration);
	    
	        byte[] buf = new byte[1024];
		int length = 0;
		while((length = sequenceInputStream.read(buf))!=-1) {			
			fileOutputStream.write(buf,0,length);			
		}		
		sequenceInputStream.close();
		fileOutputStream.close();	
	}	
}
重点:
Enumeration<FileInputStream> enumeration = vector.elements();     //  创建迭代器    
SequenceInputStream   sequenceInputStream = new SequenceInputStream(enumeration);
sequenceInputStream.read(buf)


例子: 对音频进行切分与合并
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;

public class test_1 {	
	public static void main(String[] args) throws IOException   {				
	        spilt();
		merge();
	}
//  切分  :  读入进去,切分后写入			
	public static void spilt() throws IOException {
		File file = new File("J:/清晨的美好.mp3");		
		File dir = new File("J:/music");		
		FileInputStream fileInputStream = new FileInputStream(file);
		byte[] buf = new byte[1024*1024];     //  切分出来的一小段歌曲的 大小
		int length = 0;

		for(int i=0; (length = fileInputStream.read(buf))!=-1;  i++) {   //  一个buf数组读完,写入新的音频文件
			
			FileOutputStream fileOutputStream = new FileOutputStream(new File(dir, "part"+i+".mp3"));
			fileOutputStream.write(buf,0,length);	
			fileOutputStream.close();
		}		
		fileInputStream.close();  	       
	}	
//  合并 :先读入小片音频,之后合并
	public static void merge() throws IOException {		
		File dir = new File("J:/music/");
		File[] files = dir.listFiles();	
		Vector<FileInputStream> vector = new Vector<FileInputStream>();
		for(File file : files) {
			if(file.getName().endsWith(".mp3")) {     //  查找后缀为 .mp3 的文件,变成输入流装入到 vector
				vector.add(new FileInputStream(file));   
			}	
		}
		File outfile = new File("J:/钢琴曲清晨的美好.mp3");
		FileOutputStream fileOutputStream = new FileOutputStream(outfile);
		
		Enumeration<FileInputStream> enumeration = vector.elements();
		SequenceInputStream sequenceInputStream= new SequenceInputStream(enumeration);
		byte[] buf = new byte[1024*1024];
		int length = 0;
		while((length = sequenceInputStream.read(buf))!=-1) {
			fileOutputStream.write(buf,0,length);
		}	
		fileOutputStream.close();
		sequenceInputStream.close();	
	}
}
6.  对象的输入输出流

对象的输入输出流: 对象的输入输出流,作用:用于写对象的信息与读取对象的信息。对象信息一旦写到文件上,那么对象的信息就可以做到持久化。

 *  对象输出流:  ObjectOutputStream    注意事项:

1.  对象需要写到文件上,那么对象所属类必须 实现   Serializable  接口
2.  对象的反序列化,创建对象不会调用构造方法
3.  出现错误:  调用序列化 writeobj(),之后在User类增加一个变量,再调用反序列化readobj();
       local class incompatible: stream classdesc serialVersionUID = -8851711735379258523, local class serialVersionUID = 8126229762432673517
        serialVersionUID 是用于记录class文件的版本信息,serialVersionUID这个数字是通过一个类的类名、成员、包名、工程名算出来的一个数字
4.  使用 对象输入流ObjectInputStream 反序列化的时候,会先读取文件中的serialVersionUID,然后与本地class文件的serialVersionUID进行对比,如果不一致,那么出错
5.   如果序列化与反序列化的时候可能会修改成员,可以一开始就给这个类指定一个serialVersionUID,这样jvm就不会再算这个serialVersionUID了!
6.   如果一个对象某个数据不想被序列化到硬盘上,可以使用 关键字  transient 修饰。
7.    如果一个类维护了另外一个类,另外一个类也需要实现    Serializable  接口。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Address implements Serializable{  //  如果一个类维护了另外一个类,另外一个类也需要实现 Serializable  接口。
	String country;
	String city;
	public Address(String country,String city) {
		this.country = country;
		this.city = city;
	}	
}
class User implements Serializable{    // 实现 Serializable  接口
	
	private static final long serialVersionUID = 1L;   // 给这个类指定一个serialVersionUID,这样jvm就不会再去算	
	String username;
	String password;
	transient int age;   // 关键字 transient(透明) ,这个数据不想被序列化到硬盘上
	Address address;
		
	public User(String username, String password) {
		this.password = password;
		this.username = username;
	}
	public User(String username, String password,int age,Address address) {
		this.password = password;
		this.username = username;
		this.age = age;
		this.address = address;
	}
	@Override
	public String toString() {		
		return "{用户名: " + this.username + "  密码: " + this.password + "  年龄: " + this.age + "  地址:" + this.address.city + "}";
	}
}
public class test_1 {	
	public static void main(String[] args) throws Exception   {					   
		writeobj();
		readobj();	
	}		
// 把文件中的对象信息读出来--------》 对象的反序列化
	public static void readobj() throws IOException, Exception {		
		File file = new File("J:/object.txt");	
		FileInputStream fileInputStream = new FileInputStream(file);		
		ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
		User user = (User)objectInputStream.readObject();
		System.out.println(user);    // 创建对象肯定要依赖对象所属的class文件
		objectInputStream.close();
	}	  
//  定义方法将对象的信息写到硬盘上------》对象的序列化
	public static void writeobj() throws IOException {
		Address address = new Address("中国", "杭州");
		User user = new User("付祖贤", "0101", 24, address);
		File file = new File("J:/object.txt");    //  找到目标文件
		FileOutputStream fileOutputStream = new FileOutputStream(file);   //  建立数据的输出流对象
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); //建立对象的输出流对象	
		objectOutputStream.writeObject(user);		// 把对象写出
		objectOutputStream.close();		
	}	
}

重点:

ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);

User user = (User)objectInputStream.readObject();

ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); //建立对象的输出流对象

objectOutputStream.writeObject(user); // 把对象写出



猜你喜欢

转载自blog.csdn.net/running987/article/details/81411469