IO流

在这里插入图片描述

字节流

字符流,转换流

细节:

输入流和输出流细节:

输入流:构造方法的路径,没有文件会抛出异常,FileNotFoundException,只能封装文件的路径,封装目录的路径是没意义的
输出流:构造方法的路径,没有文件会创建新文件,有文件会覆盖文件,且路径只能是文件,没有后缀名也是没有后缀名的文件,不是目录
输出流可能会有flush方法刷新缓冲区,输入流没有

字节流字符流细节:

字节是按照byte[] 输入输出或单个字节输入输出 , 字节流有available()方法,返回文件剩余字节数,字符流没有
字符流按照char[]数组输入输出或单个字节输入输出,注意writer还有按照String字符串输出的方法
字符流的输出流flush()方法,用来把数组数据刷新到文件中(数组满了会自动刷新到文件中),字节输出流(OutputStream)没有,缓冲字节流(BufferedOutputStream)有
注意:字符流用于处理纯文本信息。而其它的声音 、视频、图片等需要用字节流处理。

缓冲字符流又多了 readLine()读一行 和 newLine()写换行符

各种流的复制(包括异常处理)

文件字节流复制

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class CopyInputStream {
	public static void main(String[] args) {
		//可能用到的方法; string.getBytes();把字符串转成byte数组,在写到文件里
		//new String(byte[] b,int off,int len); 将byte数组转成字符串,控制台输出
		try (
				FileInputStream fis = new FileInputStream(new File("1.txt"));
				FileOutputStream fos = new FileOutputStream(new File("2.txt"))
		)
		{
			//定义缓冲数组
			byte[] bytes = new byte[1024];
			//定义读取个数
			int readNum = 0;
			while ((readNum = fis.read(bytes)) != -1) {
				fos.write(bytes, 0, readNum);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}		
	}
}

缓冲字节流复制

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

public class CopyBufferedInputStream {
	public static void main(String[] args) {
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			 bis = new BufferedInputStream(
					new FileInputStream(new File("1.txt")));
			 bos = new BufferedOutputStream(
					 new FileOutputStream(new File("2.txt")));
			 
			 int readNum = 0;
			 byte[] bytes = new byte[1024];
			 while ((readNum = bis.read(bytes)) != -1) {
				bos.write(bytes, 0, readNum);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if (bis != null) {
				try {
					bis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

文件字符流复制

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

public class CopyReader {
	public static void main(String[] args) {
		FileReader fr = null;
		FileWriter fw = null;
		try {
			fr = new FileReader(new File("1.txt"));
			fw = new FileWriter(new File("2.txt"));
			int readNum = 0;
			char[] cbuf = new char[1024];//字符数组
			while ((readNum = fr.read(cbuf)) != -1) {
				fw.write(cbuf, 0, readNum);//存字符数组
				fw.write(new String(cbuf, 0, readNum));//存字符串
//				fw.write(str,0,readNum);//存字符串
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fr != null) {
				try {
					fr.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			if (fw != null) {
				try {
					fw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

缓冲字符流复制

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyBufferdReader {
	public static void main(String[] args) {
		try (
				BufferedReader br = new BufferedReader(new FileReader(new File("1.txt")));
				BufferedWriter bw = new BufferedWriter(new FileWriter(new File("2.txt")));
		)
		{
			//定义读取的行
			String line = null;
			while ((line = br.readLine()) != null) {
				bw.write(line);//写字符串
				bw.newLine();//换行
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
}

复制整个文件目录

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

/**
 * 作者: 帅的一批 时间:2019年12月12日下午4:12:45 学习: 内容: 复制一个文件夹到另一个文件夹
 */
public class CopyFiles {
	public static void main(String[] args) throws IOException {
		File f1 = new File("E:\\File");
		File f2 = new File("E:\\File1");
		copyFiles2(f1, f2);
	}

	//单纯的复制文件
	public static void copyFile2(File f1, File f2) throws IOException {
		FileInputStream fis1 = new FileInputStream(f1);
		FileOutputStream fos2 = new FileOutputStream(f2);
		int readNum = 0;
		byte[] bytes = new byte[1024];
		while ((readNum = fis1.read(bytes)) != -1) {
			fos2.write(bytes, 0, readNum);
		}
		System.out.println("复制文件" + f1.getAbsolutePath() + "到" + f2.getAbsolutePath() + "成功。");
	}
	/**
	 * 
	 * @param f1 把f1复制一份给f2
	 * @param f2 把f1复制一份给f2
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static void copyFiles2(File f1, File f2) throws FileNotFoundException, IOException {

		if (f1.getAbsolutePath().equals(f2.getAbsolutePath())) {
			System.out.println("路径名一样,再见来不及握手。");
			return;
		} else if (!f1.exists()) {
			System.out.println("文件或目录不存在,再见来不及握手");
			return;
		} else if (f2.getName().contains(".")) {
			System.out.println("复制到的目录名格式错误,不要包含 '.' ");
			return;
		}

		// 如果都是文件就复制
		if (f1.isFile()) {
			System.out.println("创建" + f2.getAbsolutePath() + "目录:" + f2.mkdir());
			File newF2 = new File(f2.getAbsolutePath() + "//" + f1.getName());
			copyFile2(f1, newF2);
		}
		// 如果都是目录,就遍历copy
		if (f1.isDirectory()) {
			File[] files = f1.listFiles();
			if (files != null) {
				for (File file : files) {
					// 创建新文件路径,这个文件或文件夹与父目录一一对应。
					File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
					// 如果是文件夹就创建文件夹,如果是文件就创建文件;如果是文件夹,就继续遍历,一直找到文件为止;找到文件就复制
					if (file.isDirectory()) {
						// 目录 创建目录,修改流,再递归
						// File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
						System.out.println("创建" + newFile.getAbsolutePath() + "文件夹:" + newFile.mkdirs());
						copyFiles2(file, newFile);
					} else {
						// File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
						copyFile2(file, newFile);
					}
				}
			}
		}
	}
}

其他常见流

1.ByteArrayOutputStream 字节数组输出流(内存输出流)

放在内存中使用的,字节数组输出流又叫内存输出流。可以将数据写入到数组。
① 构造方法:
ByteArrayOutputStream()
② 常用方法:
1》write()
2》toString()将写入数组缓冲区的内容转成字符串的形式
3》 toByteArray()将写入数组缓冲区的内容转成字节数组的形式。

public class ByteArrayStreamStudy {
	public static void main(String[] args) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos.write("abcdfg".getBytes());
		System.out.println(baos.toString());
		System.out.println(Arrays.toString(baos.toByteArray()));
	}
}

2.RandomAccessFile 随机访问流(可读可写)

构造方法:
RandomAccessFile(File file, String mode)
其中 mode表示读写模式 :
r 表示只读,rw表示读写 。
2》常用方法:
seek(long pos) 设置文件指针的位置。
getFilePointer() 获取文件指针的偏移量
注意: 随机插入覆盖(从索引后开始覆盖),不是插入。

public static void main(String[] args) throws IOException {
		RandomAccessFile raf = new RandomAccessFile(new File("1.txt"), "rw");
		raf.seek(2);//设置指针位置
		int value = raf.read();
		System.out.println(raf.getFilePointer());//获取当前指针位置
		//写入
		raf.write("哈哈哈哈哈".getBytes());//插入覆盖,不是插入
		System.out.println((char)value);
		
	}

可以获取文件中任意位置的数据。比如可以获取某个字的索引,然后把它全部替换。

可用作分片上传,使用RandomAccessFile来切割文件。
https://blog.csdn.net/qq_66862911/article/details/131356420

注意:
RandomAccessFile依然 ==**不能向文件的指定位置插入内容**== ,如果直接将文件记录指针移动到中间某位置后开始输出,则**新输出的内容会覆盖文件中原有的内容**。如果需要向指定位置插入内容,程序需要先把插入点后面的内容读入缓冲区,等把需要插入的数据写入文件后,再将缓冲区的内容追加到文件后面。
/**
 * 向指定文件的指定位置插入指定的内容
 *
 * @param fileName      指定文件名
 * @param pos           指定文件的指定位置
 * @param insertContent 指定文件的指定位置要插入的指定内容
 */
public static void insert(String fileName, long pos,
                          String insertContent) throws IOException {
    RandomAccessFile raf = null;
    //创建一个临时文件来保存插入点后的数据
    File tmp = File.createTempFile("tmp", null);
    FileOutputStream tmpOut = null;
    FileInputStream tmpIn = null;
    tmp.deleteOnExit();
    try {
        raf = new RandomAccessFile(fileName, "rw");
        tmpOut = new FileOutputStream(tmp);
        tmpIn = new FileInputStream(tmp);
        raf.seek(pos);
        //--------下面代码将插入点后的内容读入临时文件中保存---------
        byte[] bbuf = new byte[64];
        //用于保存实际读取的字节数
        int hasRead = 0;
        //使用循环方式读取插入点后的数据
        while ((hasRead = raf.read(bbuf)) > 0) {
            //将读取的数据写入临时文件
            tmpOut.write(bbuf, 0, hasRead);
        }
        //----------下面代码插入内容----------
        //把文件记录指针重新定位到pos位置
        raf.seek(pos);
        //追加需要插入的内容
        raf.write(insertContent.getBytes());
        //追加临时文件中的内容
        while ((hasRead = tmpIn.read(bbuf)) > 0) {
            raf.write(bbuf, 0, hasRead);
        }
    } finally {
        if (raf != null) {
            raf.close();
        }
    }
}
获取一个字符串中某个字符出现的索引位置及次数
public static int getNumOfChar(String str,char c) {
		int count = 0;
		int index = -1;
		while ((index = str.indexOf(c, index+1)) != -1) {
			System.out.println(index);
			count++;
		}
		return count;
}

main(){
	String str = "afddsadsafdsafdsafdsafdsdsafa";
	syso(getNumOfChar(str,'s'))
}

3.打印流 PrintStream /PrintWriter

好处:打印流可以进行自动刷新,并且不会抛出 IOException。
println(char[] x) 打印字符数组时,返回值为字符数组的值。不是对象。

4.属性集 Properties

是Hashtable的子类,可以当做普通的Map使用;键值对方式
1.Properties 属性集 是一个键值对的集合。其中键与值都是字符串的形式。
2.构造方法 :
1》 Properties() 创建一个没有默认值的空属性集列表
3.常用方法:
** ① setProperty(key,value) 添加
** ② getProperty(String key) 获取
③ store(OutputStream out, String comments) 将属性集写入输出流
** ④ load(Reader reader) 将属性集加载到输入流中
get set使用

public static void main(String[] args) throws IOException {
		Properties prp = new Properties();
		System.out.println(prp);
		prp.setProperty("username","root");
		prp.setProperty("password", "123");
		System.out.println(prp);
		String name = (String) prp.get("username");
		String psw = (String) prp.get("password");
		System.out.println(name+psw);
}

把属性集写到配置文件中

	public static void main(String[] args) throws IOException {
		Properties prp = new Properties();
		System.out.println(prp);
		prp.setProperty("username","root");
		prp.setProperty("password", "123");
		System.out.println(prp);
		prp.store(new FileWriter(new File("3.txt")), "用户名和密码");//把内存中的属性集写到文件里
}

3.txt中的结果
在这里插入图片描述
读取文件中的属性集

public static void main(String[] args) throws FileNotFoundException, IOException {
		Properties prp = new Properties();
		prp.load(new FileInputStream(new File("3.txt")));
		System.out.println(prp);//{password=123, username=root}
}

5.序列化流与反序列化流(重要)

1.序列化流/对象流 ObjectOutputStream

① 序列化:实现 Serializable 接口的类 称为可序列化的类。 该接口中没有任何的方法,就是为了表示该类所创建的对象能够被序列化。
2.构造方法:
① ObjectOutputStream(OutputStream out)
3…常用方法 :
① writeObject(obj)
注意: 必须写入实现了序列化的类的对象,才可以。否则抛出java.io.NotSerializableException

2.反序列化流 ObjectInputStream

1.构造方法
ObjectInputStream(InputStream in)
2.常用方法:
1》 readObject() 返回值是Object类型,返回的是读取的对象。
注意: 该方法不能判断是否存在对象,当到达文件末尾时,抛出异常EOFException 。

普通对象序列化反序列化使用:
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.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectOutputStreamStudy {
	public static void main(String[] args) throws IOException, IOException, ClassNotFoundException {
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("4.txt")));
		oos.writeObject(new Student("zcv", 12, 99.9));// 序列化流将对象放进文件中
		oos.close();
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("4.txt")));
		Student s = (Student) ois.readObject();//读取文件中的一个对象 
		System.out.println(s.getName());
		ois.close();
	}
}

class Student implements Serializable {
	private String name;
	private int age;
	private double socore;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public double getSocore() {
		return socore;
	}

	public void setSocore(double socore) {
		this.socore = socore;
	}

	public Student(String name, int age, double socore) {
		super();
		this.name = name;
		this.age = age;
		this.socore = socore;
	}

	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}

}

集合序列化反序列化使用
package day20.io.study2;

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;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ObjectOutputStreamStudy2 {
	public static void main(String[] args) {
		List<Person> persons = new ArrayList<Person>();
		persons.add(new Person("a大师傅sf", 23));
		persons.add(new Person("sa地方撒d", 22));
		persons.add(new Person("a 大dsf", 2123));
		persons.add(new Person("a爱的方式f", 1233));
		persons.add(new Person("ad阿道夫f", 123));
		persons.add(new Person(" 安抚dsf", 33));
		try (
				ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("persons.txt")));	
		){
			oos.writeObject(persons);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try (
				ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("persons.txt")));	
		){
			ArrayList<Person> personList = (ArrayList<Person>) ois.readObject();
			Iterator<Person> it = personList.iterator();
			while (it.hasNext()) {
				Person p = it.next();
				if (p.getName().contains("a")) {
					System.out.println(p);
				}
			}
		} catch (IOException | ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class Person implements Serializable{
	/**
	 * 
	 */
//	private static final long serialVersionUID = 1L;
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}
细节
1.序列化版本号 :

(1)作用 :检测版本是否一致。
(2)serialVersionUID
①默认值为1L。一般都使用生成器生成随机值。
在这里插入图片描述
如果序列化时序列号版本号为1L,现在序列号为2L,在反序列化时会报java.io.InvalidClassException: 失效的类异常

2.序列化的对象存储问题:
1》当我们使用writeObject方法进行写入对象时,要求对象必须实现Serializable接口,
并且要求如果有对象属性,也必须实现该接口。
否则,会报在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值