第5章 JAVA输入输出操作

课程回顾

List:

有序可重复

ArrayList 基于数组存储,默认长度10,扩容1.5倍;
LinkedList 基于双向链表存储的,节点用的是静态内部类Node:包括三部分①prev上一个节点的引用②e表示数据③next下一个节点的引用,
Vector 线程安全的List, 核心方法都是加锁synchronized, 扩容2倍。

Set:

HashSet TreeSet LinkedHashSet ConcurrentHashSet; 这些本身不存储都依赖于对应的Map结构存储数据。

特点: 无序、不允许重复

Map:

键值对,key—value的映射关系; 鹿晗-----关晓彤

HashMap、TreeMap( 默认是自然顺序 Comparable接口,所有的基本数据类型的包装类都实现该接口 )可以进行比较。自定义的比较器: ①自身具备比较性,实现Comparable接口。②通过第三方的比较器: 实现接口Comparator,在创建TreeMap的时候传入这个比较器。可以是Lambad表达式简化编码。

本章简介

File类

File类是用来描述磁盘上的目录和文件,可以表示目录也可以表示文件。File类的常用方法

  • 创建文件
  • 删除文件
  • 判断文件是否存在、是否可读、可写
  • 创建目录
  • 列举目录的文件
  • 获取磁盘的信息: 包括多少分区、分区的总大小、可用大小
  • 获取文件的绝对路径

案例:

package ch005io;

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

public class Demo1 {
	//check异常、非check异常; IOExecption编译期异常
	public static void main(String[] args) throws IOException {
		listFile("D:\\eclipse-workspace\\web1");//调用递归方法
	}
	private static void test4() {
	    //获取磁盘空间信息
		File[] roots = File.listRoots();
		for (File file : roots) {
			long totalSpace = file.getTotalSpace();
			System.out.print(file.getAbsolutePath()+":");
			//                               byte      kb   mb  gb
			System.out.print("分区总大小:"+(totalSpace/1024/1024/1024));
			long freeSpace = file.getFreeSpace();
			System.out.print(",剩余总大小:"+(freeSpace/1024/1024/1024));
			long usableSpace = file.getUsableSpace();
			System.out.print(",可用空间大小:"+(usableSpace/1024/1024/1024)+"\n");
		}
	}
	private static void test3() {
		File dirs = new File("D:\\eclipse-workspace\\web1");
		String[] fileName =dirs.list((dir,name) -> name.endsWith("java"));
		for (String string : fileName) {
			System.out.println(string);
		}
	}

	//递归调用列举指定目录下的所有文件和文件夹的文件
	public static void listFile(String path) {
		File files = new File(path);
		File[] listFiles = files.listFiles();
		for (File file : listFiles) {
			if(file.isDirectory()) {
				//如果是目录:
				listFile(file.getAbsolutePath());
			}else {
				//不是目录就是文件
				System.out.println("==="+file.getAbsolutePath());
			}
		}
	}
	
	
	
	
	private static void test2() {
		//1.创建目录的方法
		File dir = new File("d:\\kong\\fu\\zi");
		System.out.println("创建文件夹:"+dir.mkdir());
		System.out.println("创建多级目录:"+dir.mkdirs());
		//2.列举目录的文件:只能是当前目录
		File dirs = new File("D:\\eclipse-workspace\\web1");
		String[] files = dirs.list();
		for (String string : files) {
			System.out.println(string);
		}
		//3.列举指定的文件
		String[] fileName =dirs.list(new FilenameFilter() {
			//两个参数: dir路径,name文件名
			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith("java");
			}
		});
		System.out.println("所有的java文件:");
		for (String string : fileName) {
			System.out.println(string);
		}
	}

	private static void test1() throws IOException {
		//1.创建文件
		File file  =new File( "d:" + File.separator + "abc.doc" );
		//windows路径分隔符";", Linux用的是":" 
		//windows文件 \  linux: /
		System.out.println("路径分隔符:"+ File.pathSeparator);
		boolean result = file.createNewFile();
		System.out.println(result);
		//2.获取文件信息
		System.out.println("绝对路径:"+file.getAbsolutePath());
		System.out.println("相对路径:"+file.getPath());
		System.out.println("文件名称:"+file.getName());
		System.out.println("文件父路径:"+file.getParent());
		System.out.println("文件大小:"+file.length());
		//3.是否可读
		System.out.println("是否可读:"+file.canRead());
		System.out.println("是否可写:"+file.canWrite());
		System.out.println("是否可执行:"+file.canExecute());
		System.out.println("得到规范文件:"+file.getCanonicalFile());
		
		//4.删除文件
		System.out.println("删除文件:"+file.delete());
	}

}

创建目录的源代码,这就是调用操作系统的接口, JNI,

/**
     * Create a new directory denoted by the given abstract pathname,
     * returning <code>true</code> if and only if the operation succeeds.
     */
public abstract boolean createDirectory(File f);

继续跟踪代码的实现:

@Override
public native boolean createDirectory(File f);

native是本地的意思,表单调用本地方法,就是操作系统的接口,C语言的接口。
在这里插入图片描述

流的使用参考:
在这里插入图片描述

字节流

区分 Java 的输入和输出:把自己当成程序,武术的最高境界:人剑合一,编码的最高境界: 人码合一,司机的最高境界:人车合一。 当你从外边读数据到自己这里就用输入(InputStream/Reader), 向外边写数据就用输出(OutputStream/Writer)。

Stream:Java 中将数据的输入输出抽象为流,流是一组有顺序的,单向的,有起点和终点的数据集合,就像水流。按照流中的最小数据单元又分为字节流和字符流。

1,字节流:以 8 位(即 1 byte,8 bit)作为一个数据单元,数据流中最小的数据单元是字节。

2,字符流:以 16 位(即 1 char,2 byte,16 bit)作为一个数据单元,数据流中最小的数据单元是字符, Java 中的字符是 Unicode 编码,一个字符占用两个字节。

FileOutputStream

定义:

public class FileOutputStream extends OutputStream
public abstract class OutputStream extends Object implements Closeable, Flushable

文件输出流是用于将数据写入到输出流File或一个FileDescriptor 。文件是否可用或可能被创建取决于底层平台。特别是某些平台允许一次只能打开一个文件来写入一个FileOutputStream (或其他文件写入对象)。在这种情况下,如果所涉及的文件已经打开,则此类中的构造函数将失败。

FileOutputStream用于写入诸如图像数据的原始字节流。 对于写入字符流,请考虑使用FileWriter

OutputStream的方法

Modifier and TypeMethod and Description
voidclose() 关闭此输出流并释放与此流相关联的任何系统资源。
voidflush() 刷新此输出流并强制任何缓冲的输出字节被写出。
voidwrite(byte[] b)b.length字节从指定的字节数组写入此输出流。
voidwrite(byte[] b, int off, int len) 从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。
abstract voidwrite(int b) 将指定的字节写入此输出流。

FileOutputStream常用方法

Constructor and Description
FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(File file, boolean append) 创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(FileDescriptor fdObj) 创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。
FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件。

方法摘要

Modifier and TypeMethod and Description
voidclose() 关闭此文件输出流并释放与此流相关联的任何系统资源。
protected voidfinalize() 清理与文件的连接,并确保当没有更多的引用此流时,将调用此文件输出流的 close方法。
FileChannelgetChannel() 返回与此文件输出流相关联的唯一的FileChannel对象。
FileDescriptorgetFD() 返回与此流相关联的文件描述符。
voidwrite(byte[] b)b.length个字节从指定的字节数组写入此文件输出流。
voidwrite(byte[] b, int off, int len)len字节从位于偏移量 off的指定字节数组写入此文件输出流。
voidwrite(int b) 将指定的字节写入此文件输出流。

案例:

package ch005io;

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

public class Demo2 {

	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("d:\\abc.txt");
		byte [] b = new byte[9];
		int len = 0;
		//while的表达式执行过程: ①先读取9个字节②把9赋值给len③len和-1比较,true或false
		while( ( len = fis.read(b)) !=-1  ) {
			System.out.println("==len=="+len);
			System.out.println("==="+new String(b,0,len));
		}
		fis.close();
	}

	private static void test2() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("d:\\abc.txt");
		byte [] b = new byte[1024];
		int len = fis.read(b);
		System.out.println(len);
		System.out.println("==="+new String(b,0,len));
		fis.close();
	}

	private static void test1() {
		FileOutputStream fos = null ;
		try {
			//默认是覆盖模式,追加模式  new FileOutputStream("d:\\abc.txt",true);
			fos = new FileOutputStream("d:\\abc.txt");
			String name  ="古力娜扎";
			fos.write(name.getBytes());
			String address = "XinJiang";
			fos.write(address.getBytes());
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(fos != null)
					fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

FileInputStream

  • FileInputStream用于读取诸如图像数据的原始字节流。
Constructor and Description
FileInputStream(File file) 通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj) 创建 FileInputStream通过使用文件描述符 fdObj ,其表示在文件系统中的现有连接到一个实际的文件。
FileInputStream(String name) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

常用方法:

Modifier and TypeMethod and Description
intavailable() 返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
voidclose() 关闭此文件输入流并释放与流相关联的任何系统资源。
protected voidfinalize() 确保当这个文件输入流的 close方法没有更多的引用时被调用。
FileChannelgetChannel() 返回与此文件输入流相关联的唯一的FileChannel对象。
FileDescriptorgetFD() 返回表示与此 FileInputStream正在使用的文件系统中实际文件的连接的 FileDescriptor对象。
intread() 从该输入流读取一个字节的数据。
intread(byte[] b) 从该输入流读取最多 b.length个字节的数据为字节数组。
intread(byte[] b, int off, int len) 从该输入流读取最多 len字节的数据为字节数组。
longskip(long n) 跳过并从输入流中丢弃 n字节的数据。

案例:注意一个UTF8字符占3个字节

private static void test3() throws FileNotFoundException, IOException {
    FileInputStream fis = new FileInputStream("d:\\abc.txt");
    byte[] b = new byte[9];
    int len = 0;
    // while的表达式执行过程: ①先读取9个字节②把9赋值给len③len和-1比较,true或false
    while ((len = fis.read(b)) != -1) {
        System.out.println("==len==" + len);
        System.out.println("===" + new String(b, 0, len));
    }
    fis.close();
}

read读取源码分析:

/**
  * Reads up to <code>b.length</code> bytes of data from this input
  * stream into an array of bytes. This method blocks until some input
  * is available.
  *
  * @param      b   the buffer into which the data is read.
  * @return     the total number of bytes read into the buffer, or
  *             <code>-1</code> if there is no more data because the end of
  *             the file has been reached.
  * @exception  IOException  if an I/O error occurs.
  */
public int read(byte b[]) throws IOException {
    return readBytes(b, 0, b.length);
}
//继续跟踪代码
/**
  * Reads a subarray as a sequence of bytes.
  * @param b the data to be written
  * @param off the start offset in the data
  * @param len the number of bytes that are written
  * @exception IOException If an I/O error has occurred.
  * 可以看出调用本地方法,native
  */
private native int readBytes(byte b[], int off, int len) throws IOException;

这就是JVM的本地方法栈的主要工作,参考文献
在这里插入图片描述

文件复制

public static void main(String[] args) {
		//从jdk1.7引入自动关闭的,不用在finally里关闭
		try(FileInputStream fis = new FileInputStream("d:\\1.jpg");
			FileOutputStream fos = new FileOutputStream("e:\\xxx.jpg");){
			//建缓冲字节数组
			byte [] b  = new byte[1024];
			int len = 0;
			while(  (len=fis.read(b)) != -1 ) {
				fos.write(b,0,len);
			}

		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}

字节缓冲流

有缓冲可以提高效率,否则每次读写都要访问磁盘,缓冲流在内部创建一个容器: 8192kb,容器临时存储,从而减少访问磁盘的次数。

public static void main(String[] args) throws Exception {
    //创建带缓冲的输入流
    FileInputStream fis = new FileInputStream("d:\\1.jpg");
    BufferedInputStream bis = new BufferedInputStream(fis);
    //创建带缓冲的输出流  使用匿名对象,因为没有直接用到fis的方法,所以可以简化编码
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\YYY.jpg"));

    //建缓冲字节数组
    byte [] b  = new byte[1024];
    int len = 0;
    while(  (len=bis.read(b)) != -1 ) {
        bos.write(b,0,len);
    }
    bos.close();
    bis.close();
}

复制视频:

public static void main(String[] args) throws Exception {
    long start = System.currentTimeMillis();

    //创建带缓冲的输入流
    String file = "E:\\OOP\\第4章 集合框架\\视频\\1.设置工作空间编码.mp4";
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);
    //创建带缓冲的输出流  使用匿名对象,因为没有直接用到fis的方法,所以可以简化编码
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\YYY.mp4"));

    //建缓冲字节数组
    byte [] b  = new byte[8192];
    int len = 0;
    while(  (len=bis.read(b)) != -1 ) {
        bos.write(b,0,len);
    }
    bos.close();
    bis.close();
    long end = System.currentTimeMillis();
    System.out.println("耗时:"+ (end-start) );
}

对象序列化

对象序列化就是把内存中的对象携带的属性信息,持久化到磁盘文件,下次再可以从文件中恢复一个对象。美国有一个富豪: 把他冷冻起来,200年之后再解冻,恢复。还有一些有故事情节的RPG游戏,可以保存磁盘。

如果一个对象要序列化则必须实现Serializable接口;相应的其关联对象也要实现Serializable接口。

序列化的实体类:

package ch005io;

import java.io.Serializable;

public class Emp implements Serializable {
	/**
	 * 这个ID号是为了在反序列化的时候进行验证的。
	 */
	private static final long serialVersionUID = 7641462444428635110L;
	private Integer id;
	private String name;
	private Dept dept;

	public Emp(Integer id, String name,Dept dept) {
		super();
		this.id = id;
		this.name = name;
		this.dept = dept;
	}
	public Integer getId() {
		return id;
	}
	
	@Override
	public String toString() {
		return "Emp [id=" + id + ", name=" + name + ", dept=" + dept + "]";
	}
	
}
//====================
package ch005io;

import java.io.Serializable;

public class Dept implements Serializable{

	private static final long serialVersionUID = -7949058275393267252L;
	private Integer deptNo;
	private String dname;
	private String loc;
	
	public Dept(Integer deptNo, String dname, String loc) {
		super();
		this.deptNo = deptNo;
		this.dname = dname;
		this.loc = loc;
	}
	@Override
	public String toString() {
		return "Dept [deptNo=" + deptNo + ", dname=" + dname + ", loc=" + loc + "]";
	}
}

案例:

package ch005io;

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

public class Demo3 {

	public static void main(String[] args) throws Exception {
		test2();
	}
	//反序列化
	private static void test2() throws IOException, FileNotFoundException, ClassNotFoundException {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\game.bin"));
		Emp emp = (Emp) ois.readObject();
		System.out.println(emp);
		ois.close();
	}
	//序列化
	private static void test1() throws FileNotFoundException, IOException {
		//节点流
		FileOutputStream fos = new FileOutputStream("d:\\game.bin");
		//包装流
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		Dept dept = new Dept(1000,"市场部","乌鲁木齐");
		Emp emp = new Emp(1001,"迪丽热巴",dept);
		oos.writeObject(emp);
		oos.close();
	}

}

序列化的时候,对象的所有属性都进行序列化了;有些特殊、关键、涉密属性最好别序列化;这就涉及到自定义序列化的属性。只需在属性上加transite即可,变成瞬时状态。

package ch005io;

import java.io.Serializable;

public class Emp implements Serializable {
	/**
	 * 这个ID号是为了在反序列化的时候进行验证的。
	 */
	private static final long serialVersionUID = 7641462444428635110L;
	private Integer id;
	private String name;
	//不进行序列化的属性
	private transient String bankCard;
	//关联属性,也要实现序列化接口
	private Dept dept;

	public Emp(Integer id, String name,String bankCard,Dept dept) {
		super();
		this.id = id;
		this.name = name;
		this.bankCard = bankCard;
		this.dept = dept;
	}
	public Integer getId() {
		return id;
	}
	@Override
	public String toString() {
		return "Emp [id=" + id + ", name=" + name + ", bankCard=" + bankCard + ", dept=" + dept + "]";
	}
	
}

测试类:

package ch005io;

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

public class Demo3 {

	public static void main(String[] args) throws Exception {
		test2();
	}
	//反序列化
	private static void test2() throws IOException, FileNotFoundException, ClassNotFoundException {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\game.bin"));
		Emp emp = (Emp) ois.readObject();
		System.out.println(emp);
		ois.close();
	}
	//序列化
	private static void test1() throws FileNotFoundException, IOException {
		//节点流
		FileOutputStream fos = new FileOutputStream("d:\\game.bin");
		//包装流
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		Dept dept = new Dept(1000,"市场部","乌鲁木齐");
		Emp emp = new Emp(1001,"迪丽热巴","1123433234",dept);
		oos.writeObject(emp);
		oos.close();
	}

}

输出结果:

Emp [id=1001, name=迪丽热巴, bankCard=null, dept=Dept [deptNo=1000, dname=市场部, loc=乌鲁木齐]]

可以看到bankCard没有序列化。如果序列化多个对象,可以放到List集合中,反序列化再用List集合接收。

字符流

字符流的由来: Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。

FileWriter类的用法

Constructor and Description
FileWriter(File file) 给一个File对象构造一个FileWriter对象。
FileWriter(File file, boolean append) 给一个File对象构造一个FileWriter对象。
FileWriter(FileDescriptor fd) 构造与文件描述符关联的FileWriter对象。
FileWriter(String fileName) 构造一个给定文件名的FileWriter对象。
FileWriter(String fileName, boolean append) 构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。

案例:

private static void test2() throws FileNotFoundException, IOException {
    FileReader reader = new FileReader("hehe.txt");
    char [] buffer = new char[1024];
    //一次读取,也可以循环读取,参考字节流
    int len  = reader.read(buffer);
    System.out.println(new String(buffer,0,len));
    reader.close();
}

private static void test1() throws IOException {
    FileWriter writer = new FileWriter("hehe.txt");
    writer.write("Java基础知识面试题(2020最新版)");
    writer.write("\n");
    writer.write("这些插件太强了,Chrome 必装!尤其程序员!");
    char [] sex = {'男','女'};
    writer.write(sex);
    writer.append("Firebug 的年代,我是火狐(Mozilla Firefox)浏览器的死忠");
    writer.flush();
    writer.close();
}

字符缓冲流

优势一次可以读取一行,提高效率。

private static void test3() throws IOException, FileNotFoundException {
    BufferedWriter bw  = new BufferedWriter(new FileWriter("d:\\123.txt"));
    bw.write("Chrome 浏览器有一个好处,就是插件极其丰富,只有你想不到的");
    bw.newLine();
    bw.write("言归正传,今天来给大家推荐 10 款我自己珍藏的 Chrome 浏览器插件。");
    bw.newLine();
    bw.close();

    //读取文件
    BufferedReader br  =new BufferedReader(new FileReader("d:\\123.txt"));
    String line = null;//存储读取的数据
    while(br.ready()) {
        line = br.readLine();
        System.out.println(line);
    }
    br.close();
}

转换流

字节到字符的转换

public static void main(String[] args) throws Exception {
    //把字节流转换成字符流,页可以是FileInputStream
    InputStreamReader isr = new InputStreamReader(System.in);
    BufferedReader br = new BufferedReader(isr);
    System.out.println("亲,请说话,输入exit退出系统。");
    String line = br.readLine();
    while(line != null) {
        if("exit".equals(line)) {
            break;
        }
        System.out.println(line);
        line = br.readLine();

    }
}

字符到字节的转换

public static void main(String[] args) throws Exception {
    //字符流到字节流的转换
    OutputStreamWriter osw = new OutputStreamWriter(System.out);
    BufferedReader br = new BufferedReader(new FileReader("d:\\abc.txt"));
    String line = br.readLine();
    while(line != null) {
        osw.write(line);
        osw.write("\n");
        line = br.readLine();

    }
    br.close();
    osw.close();
}

private static void test5() throws IOException {
    //字符流到字节流的转换
    OutputStreamWriter osw = new OutputStreamWriter(System.out);
    String str  ="Chrome 浏览器有一个好处,就是插件极其丰富,只有你想不到的,";
    osw.write(str);
    osw.close();
}

打印流

public static void main(String[] args) throws Exception {
    //字符打印流,PrintStream 字节打印流
    PrintWriter out = new PrintWriter("d:\\haha.txt");
    out.println(" crxMouse Chrome™ 手势");
    out.println(" crxMouse Chrome™ 手势");
    out.println(" crxMouse Chrome™ 手势");
    out.println(100);
    out.println(3.14);
    out.close();
}

管道流

public static void main(String[] args) throws Exception {
    PipedOutputStream pos = new PipedOutputStream();
    PipedInputStream pis = new PipedInputStream(pos);
    //张三向外倒水
    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                pos.write("迪丽热巴".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });
    //李四向里接水
    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {

            try {
                byte[] b = new byte[1024];
                int len = pis.read(b);
                System.out.println("李四接收数据:"+new String(b,0,len));
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    });

    //启动线程
    t1.start();
    t2.start();
    Thread.sleep(500);//确保两个子线程先跑
    pis.close();
}

在这里插入图片描述

合并流

package ch005io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.SequenceInputStream;

public class Demo5 {
	public static void main(String[] args) {
		FileInputStream fistream1 = null;
		FileInputStream fistream2 = null;
		SequenceInputStream sistream = null;
		FileOutputStream fostream = null;
		try {
			fistream1 = new FileInputStream("d:/A.txt");
			fistream2 = new FileInputStream("d:/B.txt");
			sistream = new SequenceInputStream(fistream1, fistream2);
			fostream = new FileOutputStream("d:/C.txt");
			int temp;//一次读取一个字符
			while ((temp = sistream.read()) != -1) {
				System.out.print((char) temp);
				fostream.write(temp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				fostream.close();
				sistream.close();
				fistream1.close();
				fistream2.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}

}

在这里插入图片描述

总结

字节流对应关系
在这里插入图片描述

字符流对应关系
在这里插入图片描述

常见面试题

1、字节流和字符流的区别?

(1)读写单位不同:字节流以字节(8 bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi 等),而字符流只能处理字符类型的数据。

(3)字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用 colse() 方法时,信息已经输出了,而字符流只有在调用 close() 方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用 flush() 方法。

2、什么是节点流,什么是处理流,它们各有什么用处,处理流的创建有什么特征?

见上文:节点流和处理流;

注意:处理流的构造器必须要 传入节点流的子类

3、什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作?

  • 对象序列化:将对象以二进制的形式保存在硬盘上;
  • 反序列化:将二进制的文件转化为对象读取;
  • 实现 serializable 接口可以实现对象序列化,其中没有需要实现的方法,implements Serializable 只是为了标注该对象是可被序列化的。

例如,在 web 开发中,如果对象被保存在了 Session 中,tomcat 在重启时要把 Session 对象序列化到硬盘,这个对象就必须实现 Serializable 接口。如果对象要经过分布式系统进行网络传输,被传输的对象就必须实现 Serializable 接口。

4、什么是 Filter 流有哪些?

FilterStream 是一种 IO 流,主要作用是用来对存在的流增加一些额外的功能,像给目标文件增加源文件中不存在的行数,或者增加拷贝的性能等。在 java.io 包中主要由 4 个可用的 filter Stream。两个字节 filter stream,两个字符 filter stream.

分别是:FilterInputStream,FilterOutputStream,FilterReader and FilterWriter. 这些类是抽象类,不能被实例化的。

FilterInputStream 流的子类:

  • DataInputStream 可以把包括基本类型在内的数据和字符串按顺序从数据源读入,它有一些特殊的方法如 readInt(),readDouble() 和 readLine() 等可以读取一个 int,double 和一个 string。
  • BufferedInputStream 增加性能。
  • PushbackInputStream 推送要求的字节到系统中。
  • 注:其它子类见 Java io 分类图。

6、说说 RandomAccessFile?

它在 java.io 包中是一个特殊的类,既不是输入流也不是输出流,它两者都可以做到。他是 Object 的直接子类。通常来说,一个流只有一个功能,要么读,要么写。但是 RandomAccessFile 既可以读文件,也可以写文件。

而且 RandomAccessFile 支持对文件的随机访问,实例可见上文:例 5,随机读写文件。

总结

很多初学者刚刚学习 java 的 IO 时会比较茫然,确实 IO 类很多,不容易记忆,不过我们可以尝试对其进行总结记忆,把流式部分概括为:两对应一桥梁一随机。

两个对应指:

  1. 字节流(Byte Stream)和字符流(Char Stream)的对应;
  2. 输入和输出的对应。
  3. 一个桥梁指:从字节流到字符流的桥梁。对应于输入和输出为InputStreamReader和OutputStreamWriter;
  4. 一个随机是:RandomAccessFile。可以随机读取文件。

增加拷贝的性能等。在 java.io 包中主要由 4 个可用的 filter Stream。两个字节 filter stream,两个字符 filter stream.

分别是:FilterInputStream,FilterOutputStream,FilterReader and FilterWriter. 这些类是抽象类,不能被实例化的。

FilterInputStream 流的子类:

  • DataInputStream 可以把包括基本类型在内的数据和字符串按顺序从数据源读入,它有一些特殊的方法如 readInt(),readDouble() 和 readLine() 等可以读取一个 int,double 和一个 string。
  • BufferedInputStream 增加性能。
  • PushbackInputStream 推送要求的字节到系统中。
  • 注:其它子类见 Java io 分类图。

6、说说 RandomAccessFile?

它在 java.io 包中是一个特殊的类,既不是输入流也不是输出流,它两者都可以做到。他是 Object 的直接子类。通常来说,一个流只有一个功能,要么读,要么写。但是 RandomAccessFile 既可以读文件,也可以写文件。

而且 RandomAccessFile 支持对文件的随机访问,实例可见上文:例 5,随机读写文件。

总结

很多初学者刚刚学习 java 的 IO 时会比较茫然,确实 IO 类很多,不容易记忆,不过我们可以尝试对其进行总结记忆,把流式部分概括为:两对应一桥梁一随机。

两个对应指:

  1. 字节流(Byte Stream)和字符流(Char Stream)的对应;
  2. 输入和输出的对应。
  3. 一个桥梁指:从字节流到字符流的桥梁。对应于输入和输出为InputStreamReader和OutputStreamWriter;
  4. 一个随机是:RandomAccessFile。可以随机读取文件。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值