Java基础-io流

File类

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

package file类;

import java.io.File;
import java.io.IOException;

public class FileDemo {
 public static void main(String[] args) {
 	File file = new File("C:\\Users\\lenovo\\Desktop\\file.txt");
 	System.out.println(file.exists());
 	if(!file.exists()) {
 		//file.mkdir();//如果不存在,则创建目录,会创建路径中的所有目录
 		try {
 			file.createNewFile();//创建一个文件
 		} catch (IOException e) {
 			e.printStackTrace();
 		}
 		System.out.println("文件已创建");
 	}
 	else {
 		file.delete();//如果文件存在则删除
 		System.out.println("文件已删除");
 	}
 }
}

RandomAccessFile类

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

(1) java文件模型
在硬盘上的文件是byte byte byte存储的,是数据的集合
(2) 打开文件
有两种模式"rw"(读写) “r”(只读)
RandomAccessFile raf = new RandomeAccessFile(file,“rw”)
文件指针,打开文件时指针在开头 pointer = 0;
(3) 写方法
raf.write(int)—>只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
(4) 读方法
int b = raf.read()—>读一个字节
(5) 文件读写完成以后一定要关闭(Oracle官方说明)

package randomAcccessFile类;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;

public class RafDemo {

	public static void main(String[] args) throws IOException {
		File file = new File("demo");
		if (!file.exists()) {
			file.mkdir();
		}

		File file1 = new File(file, "raf.dat");
		if (!file1.exists()) {
			file1.createNewFile();
		}

		RandomAccessFile raf = new RandomAccessFile(file1, "rw");
		// 指针的位置
		System.out.println(raf.getFilePointer());

		raf.write('A');// 只写了一个字节(低8位)
		System.out.println(raf.getFilePointer());
		raf.write('B');

		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());

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

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

		//读文件:必须把指针移到头部
		raf.seek(0);
		//一次性读取,把文件中的内容都读取到字节数组中
		byte[] buf = new byte[(int)raf.length()];
		raf.read(buf);
		
		System.out.println(Arrays.toString(buf));
		
		//将字节数组构造成字符串输出
		String str = new String(buf,"GBK");
		System.out.println(str);
		
		System.out.println(Arrays.toString(buf));
		
		raf.close();
	}
}

字节流

  1. InputStream、OutputStream
    InputStream抽象了应用程序读取数据的方式
    OutputStream抽象了应用程序写出数据的方式

  2. EOF = End 读到-1就读到结尾

  3. 输入流基本方法
    int b = in.read();读取一个字节无符号填充到int低八位.-1是 EOF
    in.read(byte[] buf)
    in.read(byte[] buf,int start,int size)

  4. 输出流基本方法
    out.write(int b) 写出一个byte到流,b的低8位
    out.write(byte[] buf)将buf字节数组都写入到流
    out.write(byte[] buf,int start,int size)

  5. FileInputStream—>具体实现了在文件上读取数据

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

  7. DataOutputStream/DataInputStream
    对"流"功能的扩展,可以更加方面的读取int,long,字符等类型数据
    DataOutputStream
    writeInt()/writeDouble()/writeUTF()

  8. BufferedInputStream&BufferedOutputStream
    这两个流类位IO提供了带缓冲区的操作,一般打开文件进行写入
    或读取操作时,都会加上缓冲,这种流模式提高了IO的性能
    从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
    FileOutputStream—>write()方法相当于一滴一滴地把水“转移”过去
    DataOutputStream–>writeXxx()方法会方便一些,相当于一瓢一瓢把水“转移”过去
    BufferedOutputStream—>write方法更方便,相当于一飘一瓢先放入桶中,再从桶中倒入到另一个缸中,性能提高了

package util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

//字节流:按字节流读写不会出现乱码问题
public class IOUtil {
	/**
	 * 以字节流读取指定文件的内容,按照16进制输出到控制台 并且每输出10个byte换行
	 * 
	 * @param fileName
	 * @throws IOException
	 */
	public static void printHex(String filePath) throws IOException {
		// 把文件作为字节流进行操作
		FileInputStream in = new FileInputStream(filePath);
		int b;
		int i = 1;
		while ((b = in.read()) != -1) {// 一次读取一个字节,8位
			if (b <= 0xf) {
				// 单位数前面补0
				System.out.print("0");
			}
			System.out.print(b + "|");
			System.out.print(Integer.toHexString(b));
		}
		in.close();
	}

	public static void printHexByByteArray(String filePath) throws IOException {
		FileInputStream in = new FileInputStream(filePath);
		byte[] buf = new byte[20 * 1024];

		/*
		 * 从in中批量读取字节,放入到buf这个字节数组中 从第0个位置开始放,最多放buf.length个 返回的是读到的字节的个数
		 */
		/*
		 * int byteCounts = in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
		 * 
		 * int j; for(int i = 0;i<byteCounts;i++) { if(buf[i] <= 0xf) {
		 * System.out.print("0"); } System.out.print(Integer.toHexString(buf[i])+" ");
		 * System.out.println(); }
		 */

		// 当不知byte数组是否足够大时:多次利用byte数组存放数据
		int bytes = 0;
		while ((bytes = in.read(buf, 0, buf.length)) != -1) {
			for (int i = 0; i < bytes; i++) {
				if (buf[i] <= 0xf) {
					System.out.print("0");
				}
				System.out.print(Integer.toHexString(buf[i] & 0xff) + " ");
				System.out.println();
			}
		}
	}

	/**
	 * 拷贝文件:字节批量读取:最快
	 * 
	 * @param srcFile
	 * @param obFile
	 * @throws FileNotFoundException
	 */
	public static void copyFile(File srcFile, File obFile) throws Exception {
		// 读取srcFile文件中的内容
		FileInputStream in = new FileInputStream(srcFile);
		// 向obFile写入内容
		FileOutputStream out = new FileOutputStream(obFile);

		byte[] buf = new byte[2 * 1024];
		int b = 0;

		while ((b = in.read(buf, 0, buf.length)) != -1) {// 读取文件中的内容
			// 写入
			out.write(buf, 0, b);
		}
		in.close();
		out.close();
	}

	/**
	 * 单字节带缓冲的文件拷贝
	 * 
	 * @param srcFile
	 * @param objFile
	 * @throws FileNotFoundException
	 */
	public static void copyFileByBuff(File srcFile, File objFile) throws Exception {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(objFile));
		int c;
		while ((c = bis.read()) != -1) {
			bos.write(c);
			//System.out.println(c);
		}
		bos.flush();// 刷新缓冲区
		bis.close();
		bos.close();
	}

	/**
	 * 单字节,不带缓冲进行文件拷贝:最慢
	 * 
	 * @param srcFile
	 * @param objFile
	 * @throws FileNotFoundException
	 */
	public static void copyByByteByte(File srcFile, File objFile) throws Exception {
		FileInputStream in = new FileInputStream(srcFile);
		FileOutputStream out = new FileOutputStream(objFile);
		int c;
		while ((c = in.read()) != -1) {
			out.write(c);
		}
		out.flush();
		in.close();
		out.close();
	}
	
	public static void read(File file) throws IOException {
		//FileInputStream in = new FileInputStream(file);//按当前项目的编码读取
		FileInputStream in = new FileInputStream(file);//按当前项目的编码读取
	
		int readLength = 0;
		byte[] byt = new byte[2*1024];
		
		while((readLength = in.read(byt, 0,byt.length)) != -1) {
			String str = new String(byt,0,readLength,"UTF-8");
			System.out.println(str);
		}
	}
}

字符流

  1. 编码问题

  2. 认识文本和文本文件
    java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)
    文件是byte byte byte …的数据序列
    文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果

  3. 字符流(Reader Writer)---->操作的是文本文本文件
    字符的处理,一次处理一个字符
    字符的底层任然是基本的字节序列
    字符流的基本实现:
    InputStreamReader 完成byte流解析为char流,按照编码解析
    OutputStreamWriter 提供char流到byte流,按照编码处理

    FileReader/FileWriter
    字符流的过滤器:
    BufferedReader ---->readLine 一次读一行
    BufferedWriter/PrintWriter ---->写一行

  • InputStreamReader 和 OutputStreamWriter
package 字符流;//字符流的操作的对象是文本,文本文件,默认按GBK编码解析:*操作时要以文件所在的编码进行读写*。
//字符流需要用字节流来构造
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;

import org.junit.Test;

/*InputStreamReader(将字节流转为字符流读出)和 OutputStreamWriter(将字符流转为字节流写入)
 * FileReader继承了InputStreamReader,在new对象时不用再new一个InputStream,直接给文件
 */
public class IsrAndOsw {
	@Test
	public void test() throws IOException {
		File file = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\11.txt");
		//Reader isr = new FileReader(file);//不能指定编码
		InputStreamReader isr = new InputStreamReader(new FileInputStream(file),"UTF-8");//默认项目的编码,要写文件本身的编码
	
		File fileout = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt");
		OutputStreamWriter outw = new OutputStreamWriter(new FileOutputStream(fileout),"UTF-8");//以该文件所在的编码写入
//		//方法一:
//		int c;
//		while((c = isr.read()) != -1) {
//			System.out.print((char)c);
//		}
		
		//方法二:
		char[] ch = new char[1*1024];
		int charCounts = 0;
		//返回的是读取到的字符的个数
		while((charCounts = isr.read(ch, 0, ch.length)) != -1) {
			String str = new String(ch,0,charCounts);
			outw.write(ch,0,charCounts);
			System.out.print(str);
		}
		outw.flush();
		outw.close();
	}
}
  • FileReader和FileWriter
package 字符流;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import org.junit.Test;

/*
 * FileReader和FileWriter:
 * (1)在构造时不需要像InputStreamReader和OutputStreamWriter
 *      再构造一个InputStream和OutputStream对象,已封装。
 * (2)在构造时不能指定读和写的编码格式,所以在项目编码和文件编码不一致时会产生乱码
 * 
 */
public class FrAndFw {

	@Test
	public void test() throws IOException {
		File filein = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\11.txt");
		FileReader reader = new FileReader(filein);//不能指定读取的编码格式
		
		File fileout = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt");
		FileWriter writer = new FileWriter(fileout);//可以追加
		//FileWriter writer = new FileWriter(fileout,true);
		
		int length;
		char[] ch = new char[1*1204];
		while((length = reader.read(ch,0,ch.length)) != -1) {
			writer.write(ch, 0, length);
		}
		writer.flush();
		writer.close();
		reader.close();
	}
}
  • BufferedReader、BufferedWriter以及PrintWriter
package 字符流;

import java.io.*;
import org.junit.Test;

/*
 * BufferedReader(线程安全)和BufferedWriter(线程安全)以及PrintWriter(线程安全)
 * (1)PrintWriter对BufferedWriter的构造做了简化,在内部封装了,
 *     但是这样就不能自己指定编码格式了,对于文件编码和项目编码格式不一样的情况下
 *     会出现乱码。
 */
public class BrAndBwOrPw {

	@Test
	public void test() throws IOException {
		BufferedReader reader = new BufferedReader(
				new InputStreamReader(
						new FileInputStream("D:\\就职学习\\Java\\Java基础\\测试\\src\\11.txt"),"UTF-8"));
		
//		BufferedWriter writer = new BufferedWriter(
//				new OutputStreamWriter(
//						new FileOutputStream("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt"),"UTF-8"));
		
		PrintWriter pw = new PrintWriter(new FileOutputStream("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt"));//会乱码
		
		String str;
		while((str = reader.readLine()) != null) {
			System.out.println(str);
//			writer.write(str);
//			writer.newLine();//单独写入换行操作
			
			pw.println(str);
		}
		
		reader.close();
//		writer.flush();
//		writer.close();
		pw.flush();
		pw.close();
	}
}

对象的序列化和反序列化

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

  2. 序列化流(ObjectOutputStream),是过滤流----writeObject
    反序列化流(ObjectInputStream)—readObject

  3. 序列化接口(Serializable)
    对象必须实现序列化接口 ,才能进行序列化,否则将出现异常
    这个接口,没有任何方法,只是一个标准

  4. transient关键字
    private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException
    private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException

    分析ArrayList源码中序列化和反序列化的问题

  5. 序列化中子类和父类构造函数的调用问题

package 对象序列化和反序列化;

import java.io.Serializable;
/*对象的序列化和反序列化:
 * (0)概念:将Object转换成byte序列为对象的序列化,反之称为反序列化。
 * (1)要实现对象的序列化和反序列化首先类需要实现Serializable接口,这个接口是空的
 * (2)通过 ObjectOuputStream对象oos.writeObject(object);对对象进行序列化
 *      通过ObjectInputStream对象Student stu = (Student)ois.readObject();进行对象的反序列化
 * (3)transien关键字:用transien关键字修饰的属性不会被jvm默认的序列化及反序列化(类成员变量都有默认值),
 *     但是可以自己定义完成这个元素的序列化以及反序列化:
 *   //序列化
	 private void writeObject(java.io.ObjectOutputStream s)
		        throws java.io.IOException {
		 s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化
		 s.writeInt(stuage);//自己完成suage的序列化
	 }
	 //反序列化
	 private void readObject(java.io.ObjectInputStream s)
		        throws java.io.IOException, ClassNotFoundException {
		 s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作
		 this.stuage = s.readInt();//自己完成stuage的反序列化
	 }	
   (4)在序列化过程中,如果被序列化的类中定义了writeObject 和 readObject 方法,
           虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义
           的序列化和反序列化。 如果没有这样的方法,则默认调用是 ObjectOutputStream 
           的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。
          用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,
          比如可以在序列化的过程中动态改变序列化的数值。
   (5)没有序列化接口的类是不能被反序列化的。当父类没有序列化接口的时候,
            反序列化所得的对象必须通过默认构造函数构建父类对象,一层一层地得到,
            当父类有序列化接口的时候,在序列化的时候它的字节信息已经被写在了文件里,
            反序列化的时候便可直接得到该对象而不需要再调用构造函数了。
 */
public class Student implements Serializable{

	private String stuno;
	private String stuname;
	/*transien关键字:在做对象序列化的时候让这个字段不被序列化
	 * 该元素不会进行jvm默认的序列化,也可以自己完成这个元素的序列化
	 */
	private transient 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;
	}
	
	public String toString() {
		return "Student:[stuno:" + this.stuno+
				           ";stuname:" +this.stuname + ";stuage:"
				           + this.stuage +"]"; 
	}
	
	//序列化
	 private void writeObject(java.io.ObjectOutputStream s)
		        throws java.io.IOException {
		 s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化
		 s.writeInt(stuage);//自己完成suage的序列化
	 }
	 
	 //反序列化
	 private void readObject(java.io.ObjectInputStream s)
		        throws java.io.IOException, ClassNotFoundException {
		 s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作
		 this.stuage = s.readInt();//自己完成stuage的反序列化
	 }
}


package 对象序列化和反序列化;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectSerializeDemo{
	public static void main(String[] args) throws Exception{
		String path = "D:\\就职学习\\Java\\Java基础\\io流\\src\\22.txt";
//		//1.对象序列化
//		ObjectOutputStream oos = new ObjectOutputStream(
//				new FileOutputStream(path));
//		Student stu = new Student("100","张三",20);
//
//		oos.writeObject(stu);	
//		
//		oos.flush();
//		oos.close();
//		System.out.println("成功");
		
		//2.反序列化:
		ObjectInputStream ois = new ObjectInputStream(
				new FileInputStream(path));
		
		Student stu1 = (Student)ois.readObject();
		ois.close();
		System.out.println(stu1);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值