Java IO输入输出流 笔记

		String s = "慕课ABC";
		byte[] bytes1 = s.getBytes();//转换成字节序列用的是项目默认的编码 ,编码GBK
		for(byte b : bytes1)
		{
			//把字节(转换成)int以16进制的方式显示, 只显示后8位
			System.out.println(Integer.toHexString(b & 0xff) + " ");
		}
		//gbk编码中文占用两个字节,英文占用1个字节
		//utf-8编码中文占用3个字节,英文占用1个字节
		byte[] bytes2 = s.getBytes("utf-8");
		for(byte b : bytes2)
		{
			System.out.print(Integer.toHexString(b & 0xff) + " ");
		}


//java是双字节编码, utf-16be编码 ,它中文占用两个字节,英文也是占用两个字节

当你的字节序列是某种编码时,这时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码。

String str2 = new String(bytes4, "utf-16be");

文本文件就是字节序列,可以是任意编码的字节序列。如果我们在中文机器上直接创建(如果复制过去则可以识别)文本文件,该文本文件只认识ANSI编码。


File

java.io.File类用于表示文件(目录)

File类只用于表示文件(目录)的信息(名称,大小)等,不能用于文件内容的访问

		File file = new File("D:\\javaio");
		//System.out.println(file.exists());//文件是否存在

		if(!file.exists())//是否存在
			file.mkdir();//创建目录     //file.mkdirs多级目录
		else
			file.delete();

		System.out.println(file.isDirectory());//是否是目录,是目录返回true
		System.out.println(file.isFile());//是否是文件

		//File file2 = new File("D:\\javaio\\日记1.txt");
		File file2 = new File("D:\\javaio", "日记1.txt");
		if( !file2.exists())
			try{
			   file2.createNewFile();//创建文件
		}catch(IOException e){
			e.printStackTrace();
		}
		else
			file2.delete();//文件删除掉

		//常用的file对象的API
		System.out.println(file);//file.toStrint()的内容 ,目录
		System.out.println(file.getAbsolutePath());
		System.out.println(file.getName());//文件或目录的名字
		System.out.println(file.getParent());//父目录的路径


	//列出指定目录下(包括其子目录)的所有文件
	public static void listDirectory(File dir) throws IOException
	{
		if(!dir.exists())//不存在
		{
			throw new IllegalArgumentException("目录"+dir+"不存在");
		}
		if(!dir.isDirectory())//不是目录
		{
			throw new IllegalArgumentException(dir+"不是目录");
		}
		String[] filenames = dir.list(); //list()方法用于列出当前目录下的子目录和文件名称,字符串数组,包含子目录的名称,不包含子目录下的内容
		for(String string : filenames)
		{
			System.out.println(string);
		}
		//如果要遍历子目录下的内容,就需要构造成file对象做递归操作,File提供了直接返回file对象的API
		File[] files = dir.listFiles();//返回的是直接子目录(文件)的抽象,不会做递归
		if(files != null && files.length > 0) 
		{
			for( File file : files)
			{
				if(file.isDirectory())
				{
					listDirectory(file);//递归操作
				}
				else
					System.//输出
			}
		}
	}

RandomAccessFile 

 java提供的对文件内容的访问,既可以读文件,也可以写文件,支持随机访问文件,可以访问文件的任意位置。

(1)java文件模型: 在硬盘上的文件是byte byte byte存储的,是数据的集合

(2)打开文件有两种模式   "rw"读写   "r"只读

RandomAccessFile raf = new RandomAccessFile(file, "rw");

文件指针,打开文件时,pointer = 0;

(3)写文件

raf.write(int)  只写一个字节(只能写int的后8位),同时指针指向下一个位置,准备再次写入

(4)读方法

int b = raf.read() 读一个字节

(5)文件读写完成后一定要关闭 (可能会有意想不到的错误)


文件读写过程:

File demo = new File("D:\\demo");
		if(!demo.exists())
			demo.mkdir();
		File file = new File(demo, "raf.dat");
		if(!file.exists())
			file.createNewFile();
		RandomAccessFile raf = new RandomAccessFile(file, "rw");
		System.out.println(raf.getFilePointer());//获得指针位置,此时值为0
		raf.write('A');//写A的后8位写进去,只写了一个字节
		System.out.println(raf.getFilePointer());//获得指针位置,此时值位1

		int i = 0x7fffffff;
		//用write方法每次写一个字节,如果要把i写进去就得写4次
		raf.write(i >>> 24 );//高8位
		raf.write(i >>> 16 );
		raf.write(i >>> 8 );
		raf.write(i);
		System.out.println(raf.getFilePointer());//获得指针位置,此时为5

		//可以直接写一个int
		raf.writeInt(i);

		String s = "中";
		byte[] gbk = s.getBytes("gbk");
		raf.write(gbk);
		System.out.println(raf.length());

		//读文件,必须把指针移动到头部
		raf.seek(0);
		//把文件中的内容都读到字节数组中,一次性读取
		byte[] buf = new byte[(int)raf.length()];
		raf.read(buf);
		System.out.println(Arrays.toString(buf));//输出[65, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48] 65是’A‘
		
		String s1 = new String(buf,"gbk");
		System.out.println(s1);

		for(byte b : buf)
		{
			System.out.println(Integer.toHexString(b & 0xff) + " ");
		}
		raf.close();//关闭文件

IO流(输入流,输出流)

字节流,字符流

1.字节流

(1) InputStream   OutputStream  抽象类

InputStream 抽象了应用程序读取数据的方式

OutputStream 抽象了应用程序写出数据的方式

(2)EOF = End 读到-1就读到结尾

(3)输入流 键盘输入是输入流

基本方法:

int b = in.read();//读取一个字节无符号填充到int的低8位,其他位补0

in.read(byte[] buf)读取数据填充到字节数组buf

in.read(byte[] buf,int start, int size)读取数据到字节数组buf中,从start位置开始放,最多放多少个

(4)输出流

out.write(int b)写出一个byte到流,写的是b的低8位

out.write(byte[] buf)将字节数组buf都写入到流

out.write(byte[], int start, int size)


(5)子类 FileInputStream  -->具体实现了在文件上读取数据

/读取文件内容,按照16进制输出到控制台,并且每输出10个byte换行, 一个一个字节读
public static void printHex(String fileName) throws IOException
{
	FileInputStream in = new FileInputStream(fileName);//把文件作为字节流进行读操作
	int b;
	int i = 1;
	while((b = in.read()) != -1)//读到一个字节
	{
		System.out.print(Integer.toHexString(b) + " ");
		if( i ++ % 10 == 0)
		{
			System.out.println();
		}
	}
	in.close();

}

//批量读字节
public static void printHexByByteArray(String fileName) throws IOException
{
	FileInputStream in = new FileInputStream(fileName);//把文件作为字节流进行读操作
	byte[] buf = new byte[8*1024];
	//从in中批量读取字节,放入buf这个字节数组中,从0个位置开始放,最多放buf.length个
	//返回的是读到的字节的个数
	/*
	int bytes = in.read(buf, 0, buf.length);//一次性读完,说明字节数组足够大
	int j = 1;
	for(int i = 0; i < bytes; i ++)
	{
		if(buf[i] <= 0xf)
			System.out.print("0");
		System.out.print(Integer.toHexString(buf[i]) + " ");
		if( j ++ % 10 == 0)
		{
			System.out.println();
		}
	}
	*/
	//数组不够大怎么办,解决方法
	int bytes = 0;
	int j = 1;
	while((bytes = in.read(buf, 0, buf.length)) != -1)
	{
		for(int i = 0; i < bytes; i ++)
		{
			System.out.print(Integer.toHexString(buf[i] & 0xff)+ " ");
			if(j++ % 10 == 0)
				System.out.println();
		}
	}
	in.close();
}

单字节读取不适合大文件,大文件效率很低

批量字节读取,对大文件效率高,也是我们最常用的读文件的方式


(6)FileOutputStream实现了向文件中写出byte数据的方法

//如果该文件不存在,则直接创建,如果存在,删除后创建	
FileOutputStream out = new FileOutputStream("demo/out.dat");  //如果要追加,则参数为"demo/out.data', true  true代表是否追加
out.write('A');//写出了'A'的低8位
out.write('B');//写出了'B'的低8位
int a = 10;//write只能写8位,写int需要写四次
out.write(a >>> 24);
out.write(a >>>16);
out.write(a >>> 8);
out.write(a);

byte[] gbk = "中国".getBytes("gbk");
out.write(gbk);
out.close();

/将一个文件拷贝到另一个文件    最快的
	public static void copyFile(File srcFile, File destFile) throws IOException
	{
		if( !srcFile.exists())
		{
			throw new IllegalArgumentException("文件:"+ srcFile + "不存在");
		}
		if(!srcFile.isFile())
		{
			throw new IllegalArgumentException("文件:" + srcFile + "不是文件");
		}

		FileInputStream in = new FileInputStream(srcFile);
		FileOutputStream out = new FileOutputStream(destFile);
		byte[] buf = new byte[8 * 1024];
		int b;
		while((b = in.read(buf, 0, buf.length)) != -1)
		{
			out.write(buf, 0, b);
			out.flush();//清空输出流
		}
		in.close();
		out.close();

	}

(7) DataOutputStream  DataInputStream

对"流“功能的扩展,可以更加方面的读取int long 字符等类型数据

DataOutStream 来说  writeInt()/ writeDouble /  writeUTF() 

<span style="white-space:pre">		</span>String file = "demo/dos.dat";
		DataOutputStream dos = new DataOutputStream(
			new FileOutputStream(file));
		dos.writeInt(10);
		dos.writeInt(-10);
		dos.writeLong(100);
		dos.writeDouble(10.5);
		//采用utf-8编码写出
		dos.writeUTF("中国");
		//以utf-16be编码写出
		dos.writeChars("中国");
		dos.close();

		DataInputStream dis = new DataInputStream(new FileInputStream(file));
		int i = dis.readInt();


(8) BufferedInputStream   BufferedOutputStream

这两个流类为IO提供了带缓冲区的操作,一般打开文件进行写入或者读取操作时,都会加上缓冲,

这种流模式提高了IO的性能。

//从应用程序中把数据放入文件,相当于把一缸水倒入到另一个缸中

FileOutputStream  -->write()相当于一滴一滴得把水”转移“过去

DataOutputStream   -->writeXxx()方法会方便一些,相当于一瓢一瓢的转移过去

BufferedOutputStream --->writeXxx()方法更方便,相当于一瓢一瓢水先放入桶中,再从桶中倒入到另一个缸中,性能提高

public static void copyFileByBuffer(File srcFile, File destFile) throws IOException
{
	//利用带缓冲的字节流进行文件的拷贝
	BufferedInputStream bis = new BufferedInputStream(
		   new FileInputStream(srcFile));
	BufferedOutputStream bos = new BufferedOutputStream(
		   new FileOutputStream(destFile));

	int c;
	while((c = bis.read()) != -1)
	{
		bos.write(c);
		bos.flush();//刷新缓冲区,必须写
	}
	bis.close();
	bos.close();
	
}

2. 字符流

1)编码问题

2)认识文本和文本文件

java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)

文件是 byte byte byte.... 的数据序列

文本文件是文本(char)序列按照某种编码方案(utf-8 utf-16be,gbk)序列化为byte的存储结果

3)字符流(Reader Writer) 操作的是文本文件

字符的处理,一次处理一个字符

字符的底层仍然是基本的字节序列。

字符流的基本实现  

InputStreamReader 完成byte流解析为char流,按照编码解析

OutputStreamReader 提供char流到byte流,按照编码处理

		FileInputStream in = new FileInputStream("d:\\sr.txt");
		InputStreamReader isr = new InputStreamReader(in);//默认项目的编码,操作时要写文件的编码
		
		FileOutputStream out = new FileOutputStream("d:\\sx.txt");
		OutputStreamWriter osw = new OutputStreamWriter(out);
		/*int c;
		while((c = isr.read())!= -1){
			System.out.print((char)c);
		}
		*/
		char[] buffer = new char[8 * 1024];
		int c;
		//批量读取,放入buffer这个字符数组,从第0个开始放,最多放buffer.length个
		//返回的是读到的字符的个数
		while((c = isr.read(buffer, 0,buffer.length))!= -1){
			String s = new String(buffer, 0, c);
			osw.write(buffer, 0, c);
			System.out.print(s);
		}
		osw.close();
		isr.close();


FileReader/ FileWriter 


FileReader fr = new FileReader("D:\\sr.txt");
		FileWriter fw = new FileWriter("D:\\sx.txt");//可以添加一个参数,true是否追加
		char[] buffer = new char[2056];
		int c;
		while((c = fr.read(buffer, 0, buffer.length))!= -1 ){
			fw.write(buffer, 0, c);
			fw.flush();
		}
		fr.close();
		fw.close();


方便,但是不能正确读取不是默认编码的文件,否则乱码,FileReader fr = new FileReader("D:\\sr.txt");没有第二个参数(编码方式)


字符流的过滤器

BufferedReader -->一次读一行

BufferedWriter / PrintWriter  --->写一行

//对文件进行读写操作
		BufferedReader br = new BufferedReader(
				new InputStreamReader(new FileInputStream("D:\\sr.txt")));
		/*BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(new FileOutputStream("D:\\sx.txt")));
		*/
		PrintWriter pw = new PrintWriter("D:\\sx.txt");
		String line;
		while((line = br.readLine()) != null){
			System.out.println(line);//一次读一行,并不能识别换行
			//bw.write(line);
			//单独写出换行操作
			//bw.newLine();
			//bw.flush();
			pw.println(line);
			pw.flush();
		}
		br.close();
		//bw.close();
		pw.close();

3 . 对象的序列化,反序列化

1)对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化

2)序列化流(ObjectOutStream),是过滤流  ---writeObject方法

   反序列化流(ObjectInputStream),---readObject方法

3)序列化接口(Serializable)

对象必须实现序列化接口,才能进行序列化,否则将出现异常

这个接口,没有任何方法,只是一个标准

public class Student implements Serializable {
	private String stuno;
	private String stuname;
	private int stuage;
	public Student(){}
	
	public Student(String stuno, String stuname, int stuage) {
		super();
		this.stuno = stuno;
		this.stuname = stuname;
		this.stuage = stuage;
	}

	public String getStuno() {
		return stuno;
	}
	public void setStuno(String stuno) {
		this.stuno = stuno;
	}
	public String getStuname() {
		return stuname;
	}
	public void setStuname(String stuname) {
		this.stuname = stuname;
	}
	public int getStuage() {
		return stuage;
	}
	public void setStuage(int stuage) {
		this.stuage = stuage;
	}
	@Override
	public String toString() {
		return "Student [stuage=" + stuage + ", stuname=" + stuname
				+ ", stuno=" + stuno + "]";
	}
	

}

public static void main(String[] args) throws IOException, ClassNotFoundException{
		String file = "D:\\1.dat";
		//1.对象的序列化
		/*ObjectOutputStream oos = new ObjectOutputStream(new
				FileOutputStream(file));
		Student stu = new Student("1002", "sr", 12);
		oos.writeObject(stu);
		oos.flush();
		oos.close();
		*/
		
		//对象的反序列化
		ObjectInputStream ois = new ObjectInputStream(new
				 FileInputStream(file));
		Student stu = (Student)ois.readObject();
		System.out.println(stu);
		ois.close();
		
		
	}


private  transient int stuage;//该元素不会进行jvm默认的序列化,  有些情况下有些变量不需要放在网络上传输

不代表不能序列化,也可以自己完成这个元素的序列化

4)

import java.io.Serializable;
import java.util.jar.JarException;


public class Student implements Serializable {
	private String stuno;
	private String stuname;
	private  transient int stuage;//该元素不会进行jvm默认的序列化
	public Student(){}
	
	public Student(String stuno, String stuname, int stuage) {
		super();
		this.stuno = stuno;
		this.stuname = stuname;
		this.stuage = stuage;
	}

	public String getStuno() {
		return stuno;
	}
	public void setStuno(String stuno) {
		this.stuno = stuno;
	}
	public String getStuname() {
		return stuname;
	}
	public void setStuname(String stuname) {
		this.stuname = stuname;
	}
	public int getStuage() {
		return stuage;
	}
	public void setStuage(int stuage) {
		this.stuage = stuage;
	}
	@Override
	public String toString() {
		return "Student [stuage=" + stuage + ", stuname=" + stuname
				+ ", stuno=" + stuno + "]";
	}
	
	private void writeObject(java.io.ObjectOutputStream s)
			throws java.io.IOException{
		s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化操作
		s.write(stuage);//自己完成stuage的序列化
		
	}
	
	private void readObject(java.io.ObjectInputStream s)
	throws  java.io.IOException, ClassNotFoundException{
		s.defaultReadObject();//把jvm能默认序列化的元素进行反序列操作
	    this.stuage = s.readInt();//自己完成stuage的反序列化
	}

}


5)序列化中 子类和父类构造函数的调用
一个类实现了序列化接口,其子类都可以进行序列化。


对子类对象进行反序列操作时,如果其父类没有实现序列化接口,那么其父类的构造函数会被调用

你可能感兴趣的:(Java IO输入输出流 笔记)