面试题首页 > Java基础面试题

IO面试题

001什么是IO流?

IO流就是以流的方式进行输入输出。主要用来处理设备之间的传输,文件的上传,下载和复制。
流分输入和输出,输入流从文件中读取数据存储到进程中,输出流从进程中读取数据然后写入到目标文件。

002Java 中有几种类型的流?

按照流的方向:输入流(inputStream)和输出流(outputStream)
按照实现功能分:节点流(可以从或向一个特定的地方(节点)读写数据。如 FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如 BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。)
按照处理数据的单位: 字节流和字符流。字节流继承于 InputStream 和 OutputStream, 字符流继承于Reader 和 Writer 。

003字节流和字符流的区别?

1)字节流读取的时候,读到一个字节就返回一个字节;字符流读取的时候会读到一个或多个字节(这个要根据字符流中编码设置,一般中文对应的字节数是两个,在UTF-8码表中是3个字节)
2)字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流只能处理字符数据。只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流。
3)字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。
案例1:在写操作的过程中,没有关闭字节流操作,但是文件中也依然存在了输出的内容代码如下:

public static void main(String[] args) throws Exception { 
    // 第1步:使用File类找到一个文件 
    File f = new File("d:" + File.separator + "test.txt"); // 声明File 对象 
    // 第2步:通过子类实例化父类对象 
    OutputStream out = new FileOutputStream(f); 
    // 第3步:进行写操作 
    String str = "Hello World!!!"; // 准备一个字符串 
    byte b[] = str.getBytes(); // 字符串转byte数组 
    out.write(b); // 将内容输出 
    // 第4步:关闭输出流 
    // out.close();
} 

案例2:在写操作的过程中,没有关闭字符流操作,发现文件中没有任何内容输出。代码如下:

public static void main(String[] args) throws Exception {         
    // 第1步:使用File类找到一个文件    
    File f = new File("d:" + File.separator + "test.txt");// 声明File 对象    
    // 第2步:通过子类实例化父类对象    
    Writer out = new FileWriter(f);            
    // 第3步:进行写操作    
    String str = "Hello World!!!"; // 准备一个字符串    
    out.write(str); // 将内容输出
    out.flush();     
    // 第4步:关闭输出流    
    // out.close();  
}  

这是因为字符流操作时使用了缓冲区,而在关闭字符流时会强制性地将缓冲区中的内容进行输出,但是如果程序没有关闭,则缓冲区中的内容是无法输出的。当然如果在不关闭字符流的情况下也可以使用Writer类中的flush()强制性的清空缓存,从而将字符流的内容全部输出。

004怎么样把字节流转换成字符流,说出它的步骤?

解题思路:把字节流转成字符流就要用到适配器模式,需要用到OutputStreamWriter。它继承了Writer接口,但要创建它必须在构造函数中传入一个OutputStream的实例,OutputStreamWriter的作用也就是将OutputStream适配到Writer。它实现了Reader接口,并且持有了InputStream的引用。利用转换流OutputStreamWriter.创建一个字节流对象,将其作为参数传入转换流OutputStreamWriter中得到字符流对象.

005什么是序列化?

序列化是指把对象转换为字节序列的过程,序列化后的字节流保存了对象的状态以及相关的描述信息,从而方便在网络上传输或者保存在本地文件中,达到对象状态的保存与重建的目的。
反序列化:客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。
序列化的优势:一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。三是通过序列化在进程间传递对象;

006IO如何实现序列化和反序列化?

(1)java.io.ObjectOutputStream:表示对象输出流;它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;
(2)java.io.ObjectInputStream:表示对象输入流;它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回;
注意:只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常!

序列化和反序列化的示例

public class SerialDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
	    //序列化
        FileOutputStream fos = new FileOutputStream("object.out");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        User user1 = new User("xuliugen", "123456", "male");
        oos.writeObject(user1);
        oos.flush();
        oos.close();
		//反序列化
        FileInputStream fis = new FileInputStream("object.out");
        ObjectInputStream ois = new ObjectInputStream(fis);
        User user2 = (User) ois.readObject();
        System.out.println(user2.getUserName()+ " " + 
	    user2.getPassword() + " " + user2.getSex());
        //反序列化的输出结果为:xuliugen 123456 male
    }
}
public class User implements Serializable {
    private String userName;
    private String password;
    private String sex;
    //全参构造方法、get和set方法省略
}

007PrintStream、BufferedWriter、PrintWriter 的比较?

1. PrintStream 类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream 后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream 
2.BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过 write()方法可以将获取到的字符输出,然后通过 newLine()进行换行操作。BufferedWriter 中的字符流必须通过调用 flush 方法才能将其刷出去。并且 BufferedWriter 只能对字符流进行操作。如果要对字节流操作,则使用 BufferedInputStream
3.PrintWriter 的 println 方法自动添加换行,不会抛异常,若关心异常,需要调用 checkError方法看是否有异常发生,PrintWriter 构造方法可指定参数,实现自动刷新缓存(autoflush)。

008如果我要对字节流进行大量的从硬盘读取,要用那个流,为什么?

因为明确说了是对字节流的读取,所以肯定是InputStream或者他的子类,又因为要大量读取,肯定要考虑到高效的问题,自然想到缓冲流BufferedInputStream。
原因:BufferedInputStream是InputStream的缓冲流,使用它可以防止每次读取数据时进行实际的写操作,代表着使用缓冲区。不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!并且也可以减少对磁盘的损伤。

目录

返回顶部