Java学习手册:Java IO面试问题

版权声明:本文为博主原创文章,未经博主允许不得转载,转载请务必注明出处: https://blog.csdn.net/MaybeForever/article/details/88930521

1、Java学习手册:Java基础知识点
2、Java学习手册:Java面向对象面试问题
3、Java学习手册:Java集合、泛型面试问题
4、Java学习手册:Java并发与多线程面试问题
5、Java学习手册:Java虚拟机面试问题
6、Java学习手册:Java IO面试问题
7、Java学习手册:Java反射机制面试问题
8、Java学习手册:Java网络编程面试问题
9、Java学习手册:Java异常面试问题
10、Java学习手册:Java设计模式面试问题
11、Java学习手册:Java数据库面试问题

零、Java序列化

Java学习手册:Java序列化

一、Java IO流的实现机制

在Java语言中,输入和输出都被称为抽象的流,流可以看作一组有序的字节集合,即数据在两设备之间的传输。

流的本质是数据传输,根据处理数据类型的不同,流可以分为两大类:字节流和字符流。

字节流以字节(8bit)为单位,包含两个抽象类:InputStream(输入流)和OutputStream(输出流)

字符流以字符(16bit)为单位,根据码表映射字符,一次可以读多个字节,包含两个抽象类:Reader(输入流)和Writer(输出流)

字节流和字符流最主要的区别为:字节流在在处理输入输出时不会用到缓存,而字符流用到了缓存

二、Java中有几种类型的流?

答:常见的流有两种,分别为字节流字符流。其中,字节流继承于InputStream与OutputStream字符流继承于Reader与Writer。InputStream是所有字节输入流的父类,OutputStream是所有字节输出流的父类。Reader是字符输入流的父类,Writer是字符输出流的父类。在java.io包中还有许多其他的流,流的作用主要是为了改善程序性能并且使用方便。

注:InputStream和OutPutStream这两个类虽然提供了一系列和读写数据有关的方法,但是这两个类是抽象的,不能被实例化

三、字节流与字符流

字节流可以处理所有类型的数据,如MP3、图片、文字、视频等。在读取时,读到一个字节就返回一个字节。在Java中对应的类以"stream"结尾。

字符流仅能够处理纯文本数据,如txt文本等。在读取时,读到一个或者多个字节,先查找指定的编码表,然后将查到的字符返回。在Java中对应的类都以"Reader"或"Writer"结尾。所有的字符流都是高级流。字符流是以字符(char)为单位读写数据的,一次处理一个unicode。字符流的底层仍然是基本的字节流。

实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时,使用了缓冲区在操作文件。字节流在在处理输入输出时不会用到缓存,而字符流用到了缓存

字节输出流:程序→字节流(直接操作文件)→文件

字符输出流:程序→字符流→缓存→文件

四、文件流(字节流)

(1)FOS(FileOutputStream)
FileOutputStream是文件的字节输出流,使用该流以字节为单位将数据写入文件。
java.io.FileOutputStream向文件中写出字节的输出流,这是一个低级流,数据的去向明确(文件中)。

FileOutputStream(File file)//创建一个指向File对象表示的文件中写出数据的文件输出流
FileOutputStream(String filename)//创建一个向具有指定名称文件中写出数据的文件输出流
//注:若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除。
FileOutputStream(File file, boolean append)//创建一个向指定File对象表示的文件中写出数据的文件输出流
FileOutputStream(String filename, boolean append)//创建一个向具有指定名称的文件中写出数据的文件输出流
//注:以上两个构造方法中,第二个参数若为true,那么通过该FOS写出的数据都是在文件末尾追加的。

(2)FIS(FileInputStream)
FileInputStream是文件的字节输入流,使用该流可以以字节为单位,从文件中读取数据。
java.io.FileInoutStream从文件中读取数据的流,是一个低级流。

FileInputStream(File file)//创建一个从指定File对象表示的文件中读取数据的文件输人流
FileInputStream(String name)//创建用于读取给定的文件系统中的路径名name所指定的文件的文件输入流
int read()//从此输入流中读取一个数据字节,若返回-1则表示EOF(End od File)
void write(int d)//将指定字节写入此文件输出流,这里只写给定的int值的低八位

(3)文件复制
使用流的形式完成文件的复制操作。
①创建一个FileInputStream读取源文件
②创建一个FileOutputStream向目标文件写
③循环读取每一个字节并写入文件
④关闭两个流完成复制

五、缓冲流(字节流)

(1)BOS(BufferedOutputStream)
BufferedOutputStream缓冲输出流,内部维护着一个缓冲区,每当我们向该流写数据时,都会先将数据存入缓冲区,当缓冲区已满时,缓冲流会将数据一次性全部写出。

①BOS实现写出缓冲

public void testBos() throws Exception{
	FileOutputStream fos = new FileOutputStream("demo.txt");
	//创建缓存字节输出流
	BufferedOutputStream bos = new BufferedOutputStream(fos);
	//所有字节被存入缓冲区,等待一次性写出
	bos.write("helloworld".getBytes());
	//关闭流之前,缓冲输出流会将缓冲区内容一次性写出
	//数据在缓冲区中保存直到缓冲区满后才写出
	bos.close();
}

②BOS的flush方法

void flush()//清空缓冲区,将缓冲区中的数据强制写出(一次性写出)。
//注:频繁使用该方法会提高写出次数从而降低写出效率

(2)BIS(BufferedInputStream)
BufferedInputStream是缓冲输入流。其内部维护着一个缓冲区(字节数组),使用该流在读写一个字节时,该流会尽可能多的一次性读取若干字节并存入缓冲区,然后逐一的将字节返回,直到缓冲区中的数据被全部读取完毕,会再次读取若干字节从而反复,这样就减少了读取的次数,从而提高了读取效率。

BIS是一个处理流,该流为我们提供了缓冲功能。

①BIS实现输入缓冲

public void testBis() throws Exception{
	FileInputStream fis = new FileInputStream("demo.txt");
	//创建缓存字节输入流
	BufferedInputStream bis = new BufferedInputStream(fis);
	int d = -1;
	//缓冲读入,实际上并非是一个字节一个字节从文件读取的
	while((d=bis.read()) != -1) {
		System.out.println(d+" ");
	}
	bis.close();//关闭流时只需关闭最外层的高级流即可
}

②缓冲流的方法 int read()
虽然也是返回一个字节,但实际上缓冲流会让其处理的流一次性读一组字节回来,并存入自身提供的字节数组(缓冲区),然后将第一个字节返回。这样的好处在于当我们再次调用该方法读取第二个字节时,缓冲流会直接将字节数组中的第二个字节返回,而不是再去读取。(也是通过提高了读取量,减少读取次数来提高读取效率)

(3)实现基于缓存区的文件复制

package com.haobi;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/*
 * 实现基于缓存区的文件复制
 */
public class CppyFile {
	public static void main(String[] args) throws Exception {
		//读取源文件
		FileInputStream fis = new FileInputStream("E:\\File_java\\IODemo\\demo.txt");
		//创建缓存字节输入流
		BufferedInputStream bis = new BufferedInputStream(fis);
		//向目标文件写
		FileOutputStream fos = new FileOutputStream("demo_copy.txt");
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		int d = -1;
		//缓冲读入,实际上并非是一个字节一个字节从文件读取的
		while((d=bis.read()) != -1) {
			bos.write(d);
		}
		bis.close();
		System.out.println("复制完毕!");
		bis.close();
		bos.close();
	}
}
//程序输出结果如下:
复制完毕!

六、对象流(字节流)

序列化:从数据结构转化为字节的过程
对象序列化:将Java中对象转换为字节的过程(对象→字节)
持久化:把内存上的数据写入磁盘中做长久保存的过程
(1)ObjectOutputStream
ObjectOutputStream是用来对对象进行序列化的输出流,可以将Java中的任何对象转化为一组字节后写出。

void writeObject(Object o)//将指定的对象转换为一组字节后写出

(2)ObjectInputStream
ObjectInputStream是用来对对象进行反序列化的输入流。

Object readObject()//该方法可以从流中读取字节(必须是oos将对象转换的一组字节)并转换为对应的对象

1、在反序列化时,会检测待反序列化的对象与该类定义的现有版本是否一致,若不一致,则会抛出异常,反序列化失败
2、若版本号没变,但是类定义发生了改变,那么采用兼容模式:
原来对象有的属性,现在还有的就还原;
原来对象有的属性,现在没的就忽略;
原来对象没有的属性,现在还有的则使用默认值;
例:

private static final long serialVersionUID = 1l;
//ObjectOutputStream在对对象进行序列化时有1个要求,就是需要序列化的的对象所属的类必须实现Serializable接口。

transient关键字,该关键字修饰的属性在序列化时其值将被忽略。

七、转换流(字符流)

(1)OutputStreamWriter(字符输出流)

//构造方法
OutputStreamWriter(OutputStream out)
//是将给定的输出流转换为字符输出流,通过该流写出的字符串是按照系统默认的字符集写出的。

//重载构造方法
OUtputStreamWriter(OutputStream out, String charsetName)
//该构造方法的第二个参数用来指定字符集,这样就可以按照当前指定的字符集将字符串转换为字节后写出。

(2)InputStreamReader(字符输入流)
转换过程:
在这里插入图片描述
(3)将osw.txt文件编码转换为GBK,并存入另一个文件中

package com.haobi;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/*
 * 将osw.txt文件编码转换为GBK,并存入另一个文件中
 * 思路:
 * 由于osw.txt文件中的字符数据都是以UTF-8编码转换的字节保存的,所以我们要先用UTF-8编码
 * 将每一个字符读取出来,然后再将该字符按照GBK编码写入另一个文件即可
 */
public class ChangeCharsetDemo {
	public static void main(String[] args) throws IOException{
		FileInputStream fis = new FileInputStream("osw.txt");
		InputStreamReader isr = new InputStreamReader(fis, "UTF-8");//若不写,则文件默认为GBK
		FileOutputStream fos = new FileOutputStream("osw_copy.txt");
		OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
		char[] buf = new char[100];
		int len = -1;
		while((len = isr.read(buf)) != -1) {
			osw.write(buf, 0, len);
		}
		System.out.println("转码完成!");
		osw.close();
		isr.close();
	}
}
//程序输出结果如下:
复制完毕!

八、缓冲字符流(字符流)

(1)PrintWriter
优势:1、读写字符快;2、可以以行为单位读写字符串;
缓冲字符输入输出流:BufferedReader、BufferedWriter
PrintWriter内部嵌套了BufferedWriter,所以其也具有缓冲功能,PrintWriter还提供了自动的行刷新功能。所以通常我们使用它来当作缓冲字符输出流。

//PrintWriter提供了很多构造方法,方便我们创建实例
//PrintWriter提供了用于流的嵌套(流的连接)使用的构造方法
PrintWriter(OutputStream out)
PrintWriter(Writer writer)
//若使用以流的方式创建PrintWriter,那么可以在构造方法中传入第二个参数,是一个Boolean值,该值若为true,
//则PrintWriter具有自动行刷新,意思是每当我们调用println方法写出内容后就会自动调用flush。如下:
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(Writer writer,boolean autoFlush)
//示例如下:
FileOutputStream fos = new FileOutputStream("pw.txt");
PrintWriter pw = new PrintWriter(fos, true);

(2)BufferedReader
BufferedReader是缓冲字符输入流,其内部提供了缓冲区,可以提高读取效率。

//常用构造方法
BufferedReader(Reader reader)
//可以按行读取字符串
String readLine()
//缓冲字符输出流的该方法可以按行为单位读取字符串,它会读取若干字符,直到读取了换行符为止,然后将换行符之前的所
//有字符组成一个字符串后返回,但是返回的字符串中不包含换行符。若返回null,则说明读取到末尾了,再没有数据可读。

(3)将当前程序的源文件读取出来并输出到控制台

package com.haobi;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/*
 * 将当前程序的源文件读取出来并输出到控制台
 */
public class BufferedReaderDemo {
	public static void main(String[] args) throws IOException{
		//字节流
		FileInputStream fis = new FileInputStream("demo.txt");
		//字节流→字符流
		InputStreamReader isr = new InputStreamReader(fis);
		//包装字符流(缓冲字符流只能包装字符流)
		BufferedReader br = new BufferedReader(isr);
		String line = null;
		while((line = br.readLine())!= null) {//按行读取字符串
			System.out.println(line);
		}
		br.close();
	}
}
//程序输出结果如下:
demo
second
third

九、读取一个文件,把文件中的大写字母转换成小写字母,把小写字母转换成大写字母。

package com.haobi;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/*
 * 把文件中的大写字母转换成小写字母,把小写字母转换成大写字母
 */
class MyOwnInputStream extends FilterInputStream{
	public MyOwnInputStream(InputStream in) {
		super(in);
	}
	public int read() throws IOException{
		int c = 0;
		if((c = super.read()) != -1) {
			if(Character.isLowerCase((char)c)){//把小写转换为大写
				return Character.toUpperCase((char)c);
			}else if(Character.isUpperCase((char)c)){//把大写转换为小写
				return Character.toLowerCase(c);	
			}else {//如果不是字母,保持不变
				return c;
			}
		}else {
			return -1;
		}
	}
}

public class InputStreamDemo {
	public static void main(String[] args) {
		int c;
		try {
			InputStream is = new MyOwnInputStream(new BufferedInputStream(new FileInputStream("iotest.txt")));
			while((c = is.read()) >= 0) {
				System.out.print((char)c);
			}
			is.close();
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}
}

十、RandomAccessFile

Java学习手册:RandomAccessFile

十一、File类

Java学习手册:File类

展开阅读全文

没有更多推荐了,返回首页