zoukankan      html  css  js  c++  java
  • IO流

    IO流

    概念

    IO流用来处理设备之间的数据传输

    Java对数据的操作是通过流的方式

    Java用于操作流的类都在IO包中

    分类

    graph TD A[流向] A --> 输入流 A --> 输出流 B[操作] B --> 字节流 B --> 字符流

    字节流 : 字节流可以操作任何数据, 计算机任何数据都是按照字节存储的

    字符流 : 字符流只能操作字符数据, 比较方便

    常用父类

    • 字节流的抽象父类
      • InputStream
      • OutputStream
    • 字符流的抽象父类
      • Reader
      • Writer

    操作流程

    graph LR 导入IO包中的类 --> A[进行IO异常处理] A --> 释放资源

    字节流

    FileInputStrem

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class DemoFileInputStream {
    
    	public static void main(String[] args) throws IOException {
    			// demo1();	
    		FileInputStream fis = new FileInputStream("Demo.txt");
    		int b ;
    		while((b = fis.read()) != -1) {
    			System.out.println(b);
    		}
    		fis.close();
    	}
    
    	private static void demo1() throws FileNotFoundException, IOException {
    		// 创建流对象
    		FileInputStream fis = new FileInputStream("Demo.txt");
    		
    		// 从硬盘上读取一个字节
    		int x = fis.read();		
    		int y = fis.read();		
    		System.out.println(x);
    		System.out.println(y); 
    		// 结束符是-1
    		// 关流释放资源
    		fis.close();
    	}
    
    }
    
    

    read()方法返回值为什么int

    因为字节输入流可以操作任何类型的文件, 比如图片视频等,这些文件底层都是以二进制形式存储的,如果每次读取都返回byte,有可能读到中间时候遇到11111111,而11111111是byte类型-1,程序遇到-1就会终止,所以使用int, 如果在11111111在前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255这样就可以保证整个数据读完,而结束符-1就是int类型

    10000001 byte类型-1的原码

    11111110 byte类型-1的反码

    11111111 byte类型-1的补码

    OutputStream

    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DemoFileOutputStream {
    
    	public static void main(String[] args) throws IOException {
    		// 创建字节输出流,如果没有就自动创建,如果有就会将文件清空 true是否追加,
    		FileOutputStream fos = new FileOutputStream("Test.txt",true);
            // 虽然写出的是int类型的数,但是到文件上的是一个字节,会自动取出前三个八位转换成byte类型
    		fos.write(97);
    		fos.write(98);
    		fos.write(99);
    		
    		fos.close();
    	}
    }
    
    

    字节数组拷贝

    available()方法

    • int read(byte[] b): 一次读取一个字节数组
    • write(byte [] b): 一次写入一个字节数组
    • available() 获取文件中所有的字节个数
    # 此方法在copy大文件时可能会导致内存溢出
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    public class DemoCopy {
    	public static void main(String[] args) throws IOException {
    		FileInputStream fis = new FileInputStream("Demo.txt");
    		FileOutputStream fos = new FileOutputStream("Copy.txt");
    		
    		// 创建与文件相同大小的字节数组
    		byte [] arr = new byte[fis.available()];
    		fos.write(fis.read(arr));
    		
    		fis.close();
    		fos.close();
    		System.out.println("Okay");
    	}
    }
    

    小数组copy

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DemoCopy {
    public static void main(String[] args) throws IOException {
    		FileInputStream fis = new FileInputStream("Demo.txt");
    		FileOutputStream fos = new FileOutputStream("Copy.txt");
    		
    		// 创建与文件相同大小的字节数组
    		byte [] arr = new byte[1024 * 8];
    		int len;
    		
    		// 如果没有加arr,返回的就不是字节个数,而是字节码标值
    		while((len = fis.read(arr)) != -1) {
    			fos.write(arr, 0, len);
    		}
    		
    		fis.close();
    		fos.close();
    		System.out.println("Okay");		
    	}
    }
    
    

    缓冲区Copy

    缓冲区:

    • 字节流一次读写一个数组的速度明显快于一个字节的读写速度
    • 8192字节

    BufferedInputStream

    • BufferedInputStream内置了一个缓冲区(数组)
    • 从BufferedInputStream中读取一个字节时, BufferedInputStream会一次性性文件中读取8192个字节,存在缓冲区中,返回给程序
    • 程序在读时,就不用找文件了,直接从缓冲区中获取
    • 直到缓冲区中的字节都获取完,才从新从文件中读取8192个字节

    BufferedOutputStream

    • BufferedOutputStream内置了一个缓冲区(数组)
    • 程序向流中写出字节时,不会直接写到文件, 先写到缓冲区中
    • 直到缓冲区写满,BUfferedOutputStream才会把缓冲区中的数据一次性写到文件里
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DemoBufferCopy {
    	public static void main(String[] args) throws IOException {
    		FileInputStream fis = new FileInputStream("Demo.txt");
    		FileOutputStream fos = new FileOutputStream("Copy.txt");
    		
    		BufferedInputStream bis = new BufferedInputStream(fis);
    		
    		BufferedOutputStream bos = new BufferedOutputStream(fos);
    		
    		int b ;
    		while((b = bis.read()) != -1) {
    			bos.write(b);
    		}
    		bis.close();
    		bos.close();	
    	}
    }
    

    比较读写速度

    • 小数组的读写速度快于Buffer
    • 小数组操作一个数组
    • Buffer操作两个数组

    flush()方法

    用来刷新缓冲区,刷新后再次写出

    close()方法

    用来关闭流释放资源的, 如果是带缓冲区的流对象的close()方法, 不但会关闭流,还会在关闭流之前刷新缓冲区,将缓冲区中的字节全部刷新到文件上去,关闭后不能再写入

    中文问题

    字节流读取中文

    • 字节流在读中文的时候可能会读半个中文,造成乱码

    字节流写出中文

    • 字节流直接操作字节,所以写出中文必须将字符串转化成字节数组
    • 写出回车换行write(" ".getBytes());
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DmeoChinese {
    	public static void main(String[] args) throws IOException {
    		try (
    				BufferedInputStream bis = new BufferedInputStream(new FileInputStream("Demo.txt"));
    				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.txt"));
    				){
    			byte[] arr = new byte[4];
    			int b;
    			while ((b = bis.read(arr)) != -1) {
    				System.out.println(new String(arr, 0, b));
    			}
    			bos.write("你好
    ".getBytes());
    		}	
    	}
    }
    

    图片加密

    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DemoTest1 {
    	public static void main(String[] args) throws IOException  {
    		try(
    		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("copy.png"));
    		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("demo.png"));
    		){
    			int b;
    			while((b = bis.read()) != -1) {
    				// 一个数异或两次就等于本身
    				bos.write(b ^ 123);
    			}
    		} 
    	}
    }
    

    字符流

    字符流可以直接读写字符的IO流

    字符流读取字符,先读取到字节数据,然后转换成字符,如果要写字符,需要把字符转换成字节在写入

    FileReader

    FileReader类的read()方法可以按照字符大小读取

    import java.io.FileReader;
    import java.io.IOException;
    
    public class DemoFileReader {
    
    	public static void main(String[] args) throws IOException {
    		FileReader fr = new FileReader("Demo.txt");
    		int b;
    		while((b = fr.read()) != -1) {
    			System.out.println((char)b);
    		}
            fr.close();
    	}
    }
    
    

    FileWrite

    FileWrite类的write()方法可以自动把字符转为字节写入

    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class DemoFileReader {
    
    	public static void main(String[] args) throws IOException {
    		FileReader fr = new FileReader("Demo.txt");
    		FileWriter fw = new FileWriter("Copy.txt");
    		int b;
    		while((b = fr.read()) != -1) {
    			fw.write(b);
    		}
    		fr.close();
    		fw.close();
    	}
    }
    

    什么情况下使用字符流

    字符流也可以拷贝文本文件,但是不推荐使用,因为读取时,会把字节转化为字符,写出时还要把字符转回字节

    程序需要读取一段文本,或者需要写出一段文本时候可以使用字符流

    读取的时候按照字符的大小进行读取, 不会出现半个中文的情况

    写出的时候可以直接将字符串写出,不用转换成字节数组

    字符流不可以拷贝非纯文本文件

    自定义字符数组拷贝

    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class DemoCopy {
    public static void main(String[] args) throws IOException {
    	FileReader fr = new FileReader("Demo.txt");
    	FileWriter fw = new FileWriter("Copy.txt");
    	char [] arr = new char[1024];
    	int len;
    	while((len = fr.read(arr)) != -1) {
    		fw.write(arr,0,len);
    	}
    	fr.close();
    	fw.close();
    	}
    }
    

    带缓冲的字符流

    BufferedReader

    read()方法

    读取字符时,回一次读取若干个字符到缓冲区, 然后逐个返回给程序, 降低读取文件的次数, 提高效率

    readline()方法

    可以读取一行字符(不包含换行符)

    BufferWriter

    writer()方法

    写出字符时,会先写到缓冲区,缓冲区写满时才会写到文件,降低文件写入的次数,提高效率

    newline()方法

    可以输出一个跨平台的换行符号" "

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class DemoBuffer {
    
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(new FileReader("Demo.txt"));
    		BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.txt"));
    		
    		
    		int c;
    		while((c = br.read()) != -1) {
    			bw.write(c);
    		}
    		br.close();
    		bw.close();
    	}
    
    }
    
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class DemoBuffer {
    
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(new FileReader("Demo.txt"));
    		BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.txt"));
    		
    		String line;
    		while((line = br.readLine()) != null) {
    			bw.write(line);
    			bw.newLine();
    		}
    		br.close();
    		bw.close();
    	}
    
    }
    
    

    LineNumberReader

    LineNumberReader是Buffered对象的子类,具有相同的功能, 并且可以统计行号

    方法

    • 调用getLineNumber()方法可以获取当先行号
    • 调用setLineNumber()方法可以设置当前行号
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.LineNumberReader;
    
    public class DemoLine {
    	public static void main(String[] args) throws IOException {
    		LineNumberReader lnr = new LineNumberReader(new FileReader("Demo.txt"));
    		
    		String line;
    		
    		while((line = lnr.readLine()) != null) {
    			System.out.println(lnr.getLineNumber() + " : " +line);
    		}
    	}
    
    }
    
    

    装饰设计模式

    • 耦合性不强, 被装饰类的变化与装饰类的变化无关
    public class DemoWarp {
    
    	public static void main(String[] args) {
    		Mephisto mephisto = new Mephisto(new Student());
    		mephisto.code();
    
    	}
    
    }
    interface Coder{
    	public void code();
    }
    
    class Student implements Coder{
    
    	@Override
    	public void code() {
    		System.out.println("javase");
    		System.out.println("javaweb");
    	}
    	
    }
    
    class Mephisto implements Coder{
    	// 获取被装饰类的引用
    	private Student s;
    
    	// 在构造方法中传入被装饰类的对象
    	public Mephisto(Student s) {
    		super();
    		this.s = s;
    	}
    	
    	// 对原有的功能进行升级
    	@Override
    	public void code() {
    		s.code();
    		System.out.println("ssh");
    		System.out.println("ssm");
    		System.out.println("DB");
    		System.out.println("soon");
    		
    	}
    	
    }
    

    序列流

    可以把多个字节整合成一个, 从序列流中读取数据,将被整合的第一个流开始读, 读完一个之后继续读第二个,一次类推

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.SequenceInputStream;
    
    public class DemoSequenceInputStream {
    	public static void main(String[] args) throws IOException {
    		SequenceInputStream sis = new SequenceInputStream(new FileInputStream("Demo1.txt"), new FileInputStream("Demo2.txt"));
    		
    		int b;
    		FileOutputStream fos = new FileOutputStream("Copy.txt");
    		while((b = sis.read()) != -1) {
    			fos.write(b);
    		}
    		sis.close();
    		fos.close();
    	}
    
    }
    
    

    内存输出流

    该输出流可以想内存中写数据,把内存当做缓冲区,写出之后可以一次性获取所有数据

    使用方法

    • 创建对象 new ByteArrayOutputStream()
    • 写出数据 write(int), write(byte[])
    • 获取数据 toByteArray()
    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class DemoByteArrayOutputStream {
    
    	public static void main(String[] args) throws IOException {
    
    		FileInputStream fis = new FileInputStream("Demo1.txt");
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		byte [] arr = new byte[5];
    		int len;
    		while ((len = fis.read(arr)) != -1) {
    			baos.write(arr,0,len);
    			
    		}
    		// 将缓冲区的数据全部获取出来
    		System.out.println(baos);
    		fis.close();
    	}
    }
    

    随机访问流

    概述

    RandomAccessFile类不属于流,是Object类的子类,但是它融合了InputStream和OutputStream的功能

    支持对随机访问文件的读写

    方法

    • read()
    • write()
    • seek()
    import java.io.IOException;
    import java.io.RandomAccessFile;
    
    public class DemoRandomAccessFile {
    
    	public static void main(String[] args) throws IOException {
    		RandomAccessFile raf = new RandomAccessFile("Demo1.txt", "rw");
    		// raf.write(97);
    		
    		// int x = raf.read();
    		
    		// System.out.println(x);
    		
    		raf.seek(0);
    		
    		raf.write(97);
    		
    		raf.close();
    	}
    
    }
    

    对象操作流

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.ArrayList;
    
    public class DemoObjectOutputStream {
    
    
    	public static void main(String[] args) throws IOException, ClassNotFoundException {
    		ArrayList<Person> list = new ArrayList<>();
    		list.add(new Person("Mephisto",18));
    		list.add(new Person("Mephist",18));
    		list.add(new Person("Mephis",18));
    		
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Demos.txt"));
    		for (Person person : list) {
    			oos.writeObject(person);
    		}
    		
    		oos.close();
    		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Demo.txt"));
    		
    		for (Person person : list) {
    			System.out.println(person);
    		}
    		ois.close();
    	}
    }
    
    

    数据输入输出流

    DataInputStream , DataOutputStream可以按照数据类型的大小读写数据

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DemoDataStream {
    	public static void main(String[] args) throws IOException {
    		DataOutputStream dos = new DataOutputStream(new FileOutputStream("Demo.txt"));
    		dos.writeInt(998);
    		dos.writeChars("你");
    		dos.close();
    		
    		
    		DataInputStream dis = new DataInputStream(new FileInputStream("Demo.txt"));
    		int x = dis.readInt();
    		char y = dis.readChar();
    		
    		System.out.println(x +" "+ y);
    		dis.close();
    	}
    }
    

    打印流

    该流可以很方便的将对象toString()结果输出,并自动加上换行,而且可以使用自动刷出的模式

    System.out就是一个PrintStream,其默认向控制台输出信息

    PrintStream和PrintWrite分辨是打印字节流和字符流

    只操作数据目的

    标准输出输入流

    System.in是InputStream,标准输入流, 默认可以从键盘输入读取字节数据

    System.out是PrintStream,标准输出流, 默认可以想Console中输出字符和字节数据

    修改标准输入输出流

    • 修改标准输入流 System.setIn(InputerStream)
    • 修改标准输出流 System.setOut(OutputStream)
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PrintStream;
    
    public class DemoSystemInOut {
    
    	public static void main(String[] args) throws IOException {
    		// InputStream输入流只有一个
    		//InputStream is = System.in;
    //		int x = is.read();
    //		System.out.println(x);
    		
    		System.setIn(new FileInputStream("Demo.txt"));
    		System.setOut(new PrintStream("Copy.txt"));
    		InputStream is = System.in;
    		PrintStream ps = System.out;
    		int b;
    		while((b = is.read()) != -1) {
    			ps.write(b);
    		}
    		is.close();
    		ps.close();
    	}
    }
    

    实现键盘录入两种方式

    • BufferedReader的readLine方法

      • BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    • Scanner

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Scanner;
    
    
    public class DemoSystemIn {
    
    	public static void main(String[] args) throws IOException {
    //		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    //		String line1 = br.readLine();
    //		System.out.println(line1);
    //		br.close();
    		
    		Scanner scanner = new Scanner(System.in);
    		String line2 = scanner.nextLine();
    		System.out.println(line2);
    		scanner.close();
    	}
    }
    

    Properties

    Properties类表示了一个持久的属性集

    可以保存在流中或从流中加载

    属性列表中每个键及其对应的值都是一个字符串

    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Enumeration;
    import java.util.Properties;
    
    public class DemoProperties {
    	public static void main(String[] args) throws FileNotFoundException, IOException {
    		// demo1();
    		// demo2();
    		Properties properties = new Properties();
    		properties.load(new FileReader("demo.properties"));
    
    		Enumeration<String> enumeration = (Enumeration<String>) properties.propertyNames();
    		while(enumeration.hasMoreElements()) {
    			String key = enumeration.nextElement();
    			String value = properties.getProperty(key);
    			System.out.println(key + " : " + value);
    		}
    //		Properties properties1 = new Properties();
    //		properties1.store(new FileOutputStream("Demo.txt"),null);
    //		properties1.setProperty("name", "Mephisto");
    	}
    
    	private static void demo2() {
    		Properties properties = new Properties();
    		properties.setProperty("name", "Mephisto");
    		properties.setProperty("age", "18");
    		
    		// System.out.println(properties);
    		Enumeration<String> enumeration = (Enumeration<String>) properties.propertyNames();
    		while(enumeration.hasMoreElements()) {
    			System.out.println(properties.getProperty(enumeration.nextElement()));
    		}
    	}
    
    	private static void demo1() {
    		Properties properties = new Properties();
    		properties.put("name", "Mephito");
    		System.out.println(properties);
    	}
    }
    
  • 相关阅读:
    Linux关闭You have new mail in /var/spool/mail/root提示
    表单验证提交内容不能为空的几种方法
    CSS选择器的优先级
    SQL Server BCP 资料导入导出
    软考数据库-系统开发与软件工程
    软考数据库-无损联接分解
    软考数据库-数据结构
    反转字符串, 以单词反转句子
    数组中是否存在两数之和等于目标值
    栈 (Swift数组实现栈)
  • 原文地址:https://www.cnblogs.com/mephisto03/p/9474576.html
Copyright © 2011-2022 走看看