您的位置:首页 > 职场人生

java工程师最新面试题(输入输出部分)

2016-03-27 22:22 603 查看
Q28关于system.out说法那个正确

请选择正确的答案

A system.out是一个printStream

B system.out是一个outputstream

Csystem.out是一个FilterOutputStream

Dsystem.out是一个printStream

Esystem.out在异常时,会抛出IOException

流io的好处是简单易懂,缺点是效率低。块io效率很高,但是变成比较复杂

Java i,模型设计非常优秀,它使用decorator模式,用户可以动态装配不同功能Stream,以便获得需要的功能。

Java体系输入输出操作是基于数据流(stream)的,有序的字节或者字符通过一通信通道从源文件地址传送到目的地。Java支持两个数据流:inputstream和outputsream。

Reader类类似于inputstream类,他是输入类层次中的基础类,reader支持16位unicode字符输出,而inputsream只支持8位字符输出。

BufferReader:该类支持类缓冲字符输入,他的子类lineNumberReader支持换从输入并能够追踪行数

CharArrayReader:该类能够从一个字符缓冲区中读入一个字符输入流

FilterReader:是一个抽象类,是过滤的字符输入数据流基础

InputStreamReader:该类可以把字节输入流转化为字符输入流,子类FileReader用来读取字符文件

PipedReader:该类用来从一个管道中读取字符

StringReader:高磊从一个字符串中读取字符

而面试题28中,system.out。是printStream的一个子类,而printSream继承了FilterOutputStream类,然后这个类在继承了outputsream类。Printsream对象并没有抛出ioexception

Q29 那个语句可以建立文件file.txt 的字节输入流

Inputsreamin=new InputStream(“file.txt”);

Inputsreamin=new FileReader(“file.txt“)

FileInputSreamin=new FileOutputStream(“file.txt”)

FileInputStreamin=new FileInputstream(“file.txt”)

Inputsream类的常用方法

Publicabstract int read()throwsIOException :从当前输入流中读取数据的下一个字节

Publicint read(byte b[])throws IOEception:将当前输入流中b.length字节的数据督导一个字节数组中

Publicint read(byte b[],int off,int len)throws IOEception :将输入流中的len字节数据读入一字节数组中,这个方法将保持阻塞知道有输入数据可用。

Skip(long n)从当前输入中跳过并丢弃n字节数据,返回实际跳过的字节数

Close()关闭当前输入流,并释放与它相关的任一系统资源。

Mark(intrealimit):在该输入流中标记当前位置。

Reset()将该输入流重新定位到上一次调用mark方法是标记的位置

Marksupported:测试该输入流是否支持mark和reset方法

Outputsream

Writer(int b)将指定字节写入当前输入流。

Writer(byte b [],intoff,int len)将指定字节数组中从off开始的len字节写到当前输入流

Flush 刷新当前输入流,将任意缓冲输入的字节输入到此流中

Close 关闭当前的输入流,且释放与它相关的任一系统资源

A

Q30哪个是正确的文件操作

当前文件系统中已经存在了文件file.txt,该文件包含有ascll文本,代码片段如下:

Try{

File f =newFile(“file.txt”);

outputSreamout=new FileOutputstream(f,true)

}catch(IOEception){

}

}

结果是什么

A代码不能编译

B代码可以编译运行,对该文件不会有改变

C代码可以编译并运行,并将该文件的长度设置为0

D抛出异常,因为该文件没有关闭

E代码可以编译运行,并从文件系统中删除该文件

1. file类

File类的实例表示主机文件系统中的文件。一个文件能通过一个路径指定,此路径名可以是一条绝对路径,也可以是一条线对与当前工作目录的相对路径。

File(File,String)创建一个File实例,表示指定路径指定名称文件

File(String):创建一个File实例,表示路径名是指定参数的文件

File(String,String):创建一个File实例,它的路径名是指定的路径名后跟分隔符字符和那么参数

File类常用方法如下所述

1、构造函数
[java] view
plain copy

1. public class FileDemo {
2. public static void main(String[] args){
3. //构造函数File(String pathname)
4. File f1 =new File("c:\\zuidaima\\1.txt");
5. //File(String parent,String child)
6. File f2 =new File("c:\\zuidaima","2.txt");
7. //File(File parent,String child)
8. File f3 =new File("c:"+File.separator+"abc");//separator 跨平台分隔符
9. File f4 =new File(f3,"3.txt");
10. System.out.println(f1);//c:\zuidaima\1.txt
11. }
12. }

2、创建方法
1.booleancreateNewFile() 不存在返回true存在返回false

2.boolean mkdir() 创建目录

3.boolean mkdirs() 创建多级目录

3、删除方法
1.boolean delete()

2.boolean deleteOnExit() 文件使用完成后删除
[java] view
plain copy

1. import java.io.File;
2. import java.io.IOException;
3. public class FileDemo2 {
4. public static void main(String[] args){
5. File f =new File("d:\\zuidaima\\1.txt");
6. try {
7. System.out.println(f.createNewFile());//当文件存在时返回false
8. System.out.println(f.delete());//当文件不存在时返回false
9. } catch (IOException e) {
10. // TODO Auto-generated catch block
11. e.printStackTrace();
12. }
13. }
14.}

4、判断方法
1.booleancanExecute()判断文件是否可执行

2.boolean canRead()判断文件是否可读

3.boolean canWrite() 判断文件是否可写

4.boolean exists() 判断文件是否存在

5.boolean isDirectory()

6.boolean isFile()

7.boolean isHidden()

8.boolean isAbsolute()判断是否是绝对路径文件不存在也能判断

5、获取方法
1.String getName()

2.String getPath()

3.String getAbsolutePath()

4.String getParent()//如果没有父目录返回null

5.long lastModified()//获取最后一次修改的时间

6.long length()

7.boolean renameTo(File f)

8.File[] liseRoots()//获取机器盘符

9.String[] list()

10.String[] list(FilenameFilter filter)
6、列出磁盘下的文件和文件夹
[java] view
plain copy

1. public class FileDemo3 {
2. public static void main(String[] args){
3. File[] files =File.listRoots();
4. for(File file:files){
5. System.out.println(file);
6. if(file.length()>0){
7. String[] filenames =file.list();
8. for(String filename:filenames){
9. System.out.println(filename);
10. }
11. }
12. }
13. }
14. }

7、文件过滤
[java] view
plain copy

1. import java.io.File;
2. import java.io.FilenameFilter;
3. public class FileDemo4 {
4. public static void main(String[] args){
5. File[] files =File.listRoots();
6. for(File file:files){
7. System.out.println(file);
8. if(file.length()>0){
9. String[] filenames =file.list(new FilenameFilter(){
10. //file 过滤目录 name 文件名
11. public boolean accept(File file,String filename){
12. return filename.endsWith(".mp3");
13. }
14. });
15. for(String filename:filenames){
16. System.out.println(filename);
17. }
18. }
19. }
20. }
21. }

8、File[] listFiles()
File[]listFiles(FilenameFilter filter)

9、利用递归列出全部文件
[java] view
plain copy

1. public class FileDemo5 {
2. public static void main(String[] args){
3. File f =new File("e:\\zuidaima");
4. showDir(f);
5. }
6. public static void showDir(File dir){
7. System.out.println(dir);
8. File[] files =dir.listFiles();
9. for(File file:files){
10. if(file.isDirectory())
11. showDir(file);
12. else
13. System.out.println(file);
14. }
15. }

10、移动文件
找出d盘下所有的 .java文件,拷贝至 c:\jad目录下,并将所有文件的类型由.java修改为.jad

[java] view
plain copy

1. public class Test5 {
2. public static void main(String[] args){
3. File f1 = new File("d:\\");
4. moveFile(f1);
5. }
6. public static void moveFile(File dir){
7. File[] files=dir.listFiles();
8. for(File file:files){
9. if(file.isDirectory())
10. moveFile(file);
11. else{
12. if(file.getName().endsWith(".java"))
13. file.renameTo(new File("c:\\jad\\"+
14. file.getName().substring(0,file.getName().lastIndexOf('.'))+".jad"));
15. }
16. }
17. }
18.}

FileoutputStream

论是二进制数据还是字符数据(文本数据)都可以用文件输出流 java.io.FileOutputStream以字节流的方式保存到所指定文件。不过,如果写字符数据,FileWriter更方便一些。FileWriter除了提供了文件写入功能之外,还内置了字符编码功能。(关于
FileWriter的使用,请参考本站相关文章)
java.io.FileOutputStream 类继承和重写了抽象类 java.io.OutputStream。他们两个都是从最早的JDK,
JDK1.0就已经存在的类。

[父类 OutputStream]
抽象类OutputStream是所有字节输出流的基类,它共定义了一个构造方法和五个方法。构造方法什么也没做。在五个方法中,有,
· 三个 Write方法:
public abstract voidwrite(int b) throws IOException
向输出流里写入一个值为 b的字节。需要注意的是,实际写入的是 int类型
b 的低8位,其余的 24位被忽略。

如果有错误,则抛出 IOException。调用这个方法时,需要捕获和处理 IOException。这个方法是OutputStream类的唯一的抽象方法,需要具体类必须实现。一般的例程为参看下面示例程序。
public void write(byte[]b) throws IOException
向输入流里写入一个字节数组b。效果和 write(b, 0, b.length)相同。调用这个方法时,需要捕获和处理
IOException。OutputStream 和FileOutputStream 的实现都是调用了下面的方法。
public voidwrite(byte[] b, int off, int len) throws IOException
把位置为 off、长度为len的字节数组b中的数据写入到输出流中。OutputStream的实现是反复调用write(int
b),子类应该提供更有效率的实现。如果 b是 null,
则抛出NullPointerException。如果off或者 len
小于0,或者 off+ len大于数组 b
的长度,则抛出IndexOutOfBoundsException。

FileOutputStream 重写了这个方法。

下面用一段例程演示 void write(int b) 和 void write(byte[]b)的使用:

//TestFileOutputStream.java

import java.io.*;
public classTestFileOutputStream

{

public static void testWrite()

{

try{

FileOutputStream fo = newFileOutputStream("MyOut.dat");

fo.write(0);

fo.write(0x43);

fo.write(0x44);

//fo.flush(); // 如果OutputStream的实现使用了缓存,这个方法用于清空缓存里的数据,并通知底层去进行实际的写操作

//FileOutputStream 没有使用缓存,因此这个方法调用与否在这个例子的运行结果没有影响。
fo.close(); //注意:如果用户忘记关闭打开的文件,系统可以通过 finalyze方法在垃圾回收的时候替用户关闭这个流。

//虽然如此,用户应该显示的调用这个方法。

}catch(IOException e)

{

e.printStackTrace();

}

}

public static void testWriteBytes()

{

try{

// 构造一个要写的数据:

byte[] data = "这个例子测试文件写".getBytes("GB2312");

FileOutputStream fo = newFileOutputStream("MyOut1.data");

fo.write(data);

//fo.flush(); //如果OutputStream的实现使用了缓存,这个方法用于清空缓存里的数据,并通知底层去进行实际的写操作

//FileOutputStream 没有使用缓存,因此这个方法调用与否在这个例子的运行结果没有影响。

fo.close();

}catch(Exception e)

{

e.printStackTrace();

}

}

public static void main(String[]args)

{
testWrite();

testWriteBytes();

}

}

· 其余两个方法
public voidflush() throws IOException

如果OutputStream的实现使用了缓存,这个方法用于清空缓存里的数据,并通知底层去进行实际的写操作。需要注意的是,这个缓存特指Java层的缓存。这个方法对底层(如操作系统)的缓存不起作用。参见
FileDescriptor。
OutputStream中这个方法的实现什么也没做。具体子类应该重写这个方法。FileOutputStream没有使用缓存,因此没有重写这个方法。因此,上面代码示例中,这个方法调用与否对运行结果没有影响。

public voidclose() throws IOException
这个方法用于关闭流。虽然,如果用户忘记调用这个方法,系统可以通过 finalyze方法在 OutputStream对象垃圾回收的时候替用户关闭这个流。但用户应该养成良好的习惯显示的调用这个方法!
OutputStream中这个方法的实现什么也没做。具体子类应该重写这个方法。java.io.FileOutputStream 重写了这个方法。 用于真正关闭相应的文件资源。

[FileOutputStream的其他方法]:
java.io.FileOutputStream 除了重写OutputStream中上述四个方法之外,还提供了额外三个方法:

protected void finalize() throws IOException 。这个方法其实是重写了
Object 中的这个方法(Object是所有Java
类(包括数组类型)的“根级”父类)。这个方法是被 Java虚拟机中的垃圾回收器调用的。用于
Java对象已经不存在了但它占有的资源没有释放的情况。FileOutputStream实现中,这个方法主要是调用了 close()方法。上面例子中,如果用户没有调用
close()方法,系统就通过这个方法在垃圾回收的时候关闭文件。但写程序时应该养成显示关闭文件的习惯。

public final FileDescriptor getFD() throws IOException。这个方法返回 FileDescriptor 对象,这个对象表示这个文件流对应的文件系统中的实际文件。
关于 FD的使用,请参见本站相关文章。

public FileChannel getChannel()这是在
JDK1.4 中引入的方法。用于支持New IO的特性。这个方法返回 FileChannel对象,这个对象表示这个文件对应的文件系统中的通道。关于Channel和
NewIO,请参阅本站其它文章。

[关于 FileOutputStream 的构造]
FileOutputStream提供了五个构造方法:
FileOutputStream(Filefile) throws FileNotFoundException 和 FileOutputStream(String name) throwsFileNotFoundException 都是通过实际文件路径(或其标识的File对象)来创建文件流。需要注意的是,如果文件不存在,(待查:是否会创建文件)。如果文件存在,则这两个构造方法中有打开文件的操作。如果文件给定的是目录而不是文件,或者文件不存在又不能创建,或者文件存在却不能打开,则抛出
FileNotFoundException 异常。如果文件由于安全保护而不允许读取,则抛出 SecurityException异常。

写文件需要考虑的一个问题是,是从文件头写入(覆盖原有数据),还是从文件尾写入(增加数据)。上面的两个构造方法都是按照前者实现的,针对后者的情况,FileOutputStream提供另外两个构造方法:
FileOutputStream(Filefile, boolean append) throws FileNotFoundException 和FileOutputStream(String name,
boolean append) throws FileNotFoundException
这两个构造方法多了一个 append参数,如果参数值是 true,则是“增加数据”,如果参数值是
false,则是“覆盖原有数据”。即,退化成前两种构造方法。

最后,同 FileInputStream 一样, FileOutputStream提供了用已经打开的文件来创建一个新的文件流:
public FileInputStream(FileDescriptor fdObj)这个构造方法里没有打开文件操作。输入的
FD 对应的一定是一个已经打开的文件。

有一个有趣的问题:如果我用同一个 FileDescriptor对象创建两个流:一个输入流,一个输出流。他们能同时进行读写操作吗?下面的示例代码给出试验:

还有一个问题: 是否允许对同一个文件打开多个流,
FileReader和FileWriter

ava中的 FileWriter类 和 FileReader类的一些基本用法

1,FileWriter类(字符输出流类)

构造方法:FileWriterfw = new FileWriter(String fileName);//创建字符输出流类对象和已存在的文件相关联。文件不存在的话,并创建。

如:FileWriterfw = new FileWriter("C:\\demo.txt");

FileWriter fw = new FileWriter(StringfileName,boolean append);//创建字符输出流类对象和已存在的文件相关联,并设置该该流对文件的操作是否为续写。

如:FileWriterfw = new FileWriter("C:\\demo.txt",ture); //表示在fw对文件再次写入时,会在该文件的结尾续写,并不会覆盖掉。

主要方法: voidwrite(String str) //写入字符串。当执行完此方法后,字符数据还并没有写入到目的文件中去。此时字符数据会保存在缓冲区中。

此时在使用刷新方法就可以使数据保存到目的文件中去。

viodflush() //刷新该流中的缓冲。将缓冲区中的字符数据保存到目的文件中去。

viodclose() //关闭此流。在关闭前会先刷新此流的缓冲区。在关闭后,再写入或者刷新的话,会抛IOException异常。

[java] view
plain copy

1. package filewriter;
2.
3. import java.io.FileWriter;
4. import java.io.IOException;
5.
6. public class Filewriter {
7.
8. private static final String LINE_SEPARATOR = System.getProperty("line.separator");
9.
10. /**
11. *
12. * @param args
13. * @throws IOException
14. */
15. public static void main(String[] args) throws IOException {
16. /**
17. * 创建一个可以往文件中写入字符数据的字符流输出流对象
18. * 创建时必须明确文件的目的地
19. * 如果文件不存在,这回自动创建。如果文件存在,则会覆盖。
20. * 当路径错误时会抛异常
21. *
22. * 当在创建时加入true参数,回实现对文件的续写。
23. */
24. FileWriter fw = new FileWriter("C:\\demo1.txt",false);
25. /**
26. * 调用该对象的write方法,向文件写入字符。
27. *
28. * 其实写入到了临时存储缓冲区中
29. */
30.// fw.write("hello \r\nworld!");//windows中的换行为\r\n unix下为\r。
31. fw.write("aello"+LINE_SEPARATOR+"world!");
32. fw.write("hahaha");
33. /**
34. * 进行刷新,将字符写到目的地中。
35. */
36.// fw.flush();
37. /**
38. * 关闭流,关闭资源。在关闭前会调用flush方法 刷新缓冲区。关闭后在写的话,会抛IOException
39. */
40. fw.close();
41.
42.
43. }
44.
45. }

关于FileWriter的的异常处理。

[java] view
plain copy

1. package filewriter;
2.
3. import java.io.FileWriter;
4. import java.io.IOException;
5.
6. public class IOExceptionDemo {
7.
8. private static final String LINE_SEPARATOR = System.getProperty("line.separator");
9. public static void main(String[] args) {
10.
11. FileWriter fw = null;
12. try {
13. fw = new FileWriter("k:\\Demo.txt", true);
14. fw.write("hello" + LINE_SEPARATOR + "world!");
15. } catch (Exception e) {
16. System.out.println(e.toString());
17. } finally {
18. if (fw != null)
19. try {
20. fw.close();
21. } catch (IOException e) {
22. throw new RuntimeException("关闭失败!");
23. }
24. }
25. }
26.}

2,FileReader类

1,构造方法

FileReaderfr = new FileReader(String fileName);//使用带有指定文件的String参数的构造方法。创建该输入流对象。并关联源文件。

2,主要方法

intread(); // 读取单个字符。返回作为整数读取的字符,如果已达到流末尾,则返回-1。

intread(char []cbuf);//将字符读入数组。返回读取的字符数。如果已经到达尾部,则返回-1。

voidclose();//关闭此流对象。释放与之关联的所有资源。

[java] view
plain copy

1. package Filereader;
2.
3. import java.io.FileReader;
4. import java.io.IOException;
5.
6. public class FileReaderDemo {
7.
8. public static void main(String[] args) throws IOException {
9. /**
10. * 创建读取字符数据的流对象。
11. * 读取路径不正确时会抛 IOException
12. * 用以个读取流对象关联一个已存在文件。
13. */
14. FileReader fr = new FileReader("demo.txt");
15. /**
16. * 用Reader中的read方法读取字符。
17. */
18. /*int ch = fr.read();
19. System.out.print((char)ch);
20. int ch1 = fr.read();
21. System.out.print((char)ch1);
22. int ch2 = fr.read();
23. System.out.print((char)ch2);*/
24. int ch = 0;
25. while((ch = fr.read()) != -1){
26. System.out.print((char)ch);
27. }
28. fr.close();
29. }
30.}

用FileReader 和 FileWriter写的复制文本文件的小程序。

[java] view
plain copy

1. package IOtest;
2.
3. import java.io.FileNotFoundException;
4. import java.io.FileReader;
5. import java.io.FileWriter;
6. import java.io.IOException;
7.
8. public class TxtCopy {
9.
10. /**
11. * 将C:\\的myHeart.txt copy 到 D:\\下
12. *
13. * 首先创建Reader读取数据数据的 读取流对象。
14. *
15. * @throws FileNotFoundException
16. */
17. public static void main(String[] args) {
18. FileReader fr = null;
19. FileWriter fw = null;
20. try {
21. fr = new FileReader("C:\\my.txt");
22. fw = new FileWriter("D:\\you.txt");
23. //读一个字符,写一个字符方法
24.// int ch = 0;
25. //
26.// while ((ch = fr.read()) != -1) {
27. // fw.write(ch);
28.// }
29. char []buf = new char[1024];
30. int len = 0;
31. //读一个数组大小,写一个数组大小方法。
32. while((len = fr.read(buf)) != -1){
33. fw.write(buf, 0, len);
34. }
35.
36. } catch (Exception e) {
37. System.out.println(e.toString());
38. } finally {
39. if (fr != null)
40. try {
41. fr.close();
42. } catch (Exception e2) {
43. throw new RuntimeException("关闭失败!");
44. }
45. if (fw != null)
46. try {
47. fw.close();
48. } catch (IOException e) {
49. throw new RuntimeException("关闭失败!");
50. }
51. }
52. }
53. }

Inputsream和outputstream区别

FileInputStream 用于读取本地文件中的字节数据,继承自InputStream类
构造方法摘要
FileInputStream(File file)

通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(FileDescriptor fdObj)

通过使用文件描述符 fdObj 创建一个FileInputStream,该文件描述符表示到文件系统中某个实际文件的现有连接。
FileInputStream(String name)

通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名 name 指定。
方法摘要
int
available()

返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
void
close()

关闭此文件输入流并释放与此流有关的所有系统资源。
protected void
finalize()

确保在不再引用文件输入流时调用其close 方法。
FileChannel
getChannel()

返回与此文件输入流有关的唯一FileChannel 对象。
FileDescriptor
getFD()

返回表示到文件系统中实际文件的连接的 FileDescriptor 对象,该文件系统正被此FileInputStream 使用。
int
read()

从此输入流中读取一个数据字节。
int
)]read(byte[] b)

从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
int
, int, int)]read(byte[] b, int off, int len)

从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
long
skip(long n)

从输入流中跳过并丢弃 n 个字节的数据。
其中read()返回的是读入的一个字节所对应的int值(0-255),而)]read(byte[]
b) 和, int, int)]read(byte[]
b, int off, int len) 返回的是读入的字节数

FileOutputStream用于将字节数据写出到文件。继承自OutputStream类
构造方法摘要
FileOutputStream(File file)

创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file,
boolean append)

创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(FileDescriptor fdObj)

创建一个向指定文件描述符处写入数据的输出文件流,该文件描述符表示一个到文件系统中的某个实际文件的现有连接。
FileOutputStream(String name)

创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(String name,
boolean append)

创建一个向具有指定 name 的文件中写入数据的输出文件流。
方法摘要
void
close()

关闭此文件输出流并释放与此流有关的所有系统资源。
protected void
finalize()

清理到文件的连接,并确保在不再引用此文件输出流时调用此流的 close 方法。
FileChannel
getChannel()

返回与此文件输出流有关的唯一FileChannel 对象。
FileDescriptor
getFD()

返回与此流有关的文件描述符。
void
)]write(byte[] b)

将 b.length 个字节从指定 byte 数组写入此文件输出流中。
void
, int, int)]write(byte[] b, int off, int len)

将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
void
write(int b)

将指定字节写入此文件输出流。
实例代码:使用这两个类进行文件复制:

[java] view
plain copy

1. import java.io.FileInputStream;
2. import java.io.FileOutputStream;
3. import java.io.IOException;
4. class IODemo
5. {
6. public static void main(String[] args)
7. {
8. try
9. {
10. //使用FileInputStream和FileOutputStream进行文件复制
11. FileInputStream fis=new FileInputStream("a.txt");
12. FileOutputStream fos=new FileOutputStream("b.txt");
13. int read;
14. //read=fis.read();
15. byte b[]=new byte[1024];
16. //读取文件,存入字节数组b,返回读取到的字符数,存入read,默认每次将b数组装满
17. read=fis.read(b);
18. while(read!=-1)
19. {
20. fos.write(b,0,read);
21. read=fis.read(b);
22. //read=fis.read();
23. }
24. fis.close();
25. fos.close();
26. }
27. catch (IOException e)
28. {
29. e.printStackTrace();
30. }
31.
32. }
33. }

上述的例子采用也可以只使用对象fis的read()方法,逐个字节的读入数据,然后用对象fos的write()这个字节输出。

注:FileInputStream和FileOutputStream适用于操作于任何形式的文件(因为是以字节为向导),如果想要操作文本文件,采用FileInputReader和FileOutputWriter效率更高。
Q31那个方法能够获得file.txt文件的父路径

A string name=File.getParentName(“file.txt”);
B String name=(new File(“file.txt”)).getParent();
C String name=(new File(:file.txt”)).getParentName();
D String name=(new File(“file.txt)).getParentFile();
E Directory dir =(new File(“file.txt)).getParentDir();

D
Q32将“hello”字符写入文件file.txt末尾
A Outputstream out =new FileOutPutStream(“file.txt”);
Out.wirteBytes(“hello”)
B Outputstream out =new FileOutPutStream(“file.txt”,true);
DataPutputStream out=newDataOutputStream(os);
Out.writerBytes(“hello”)
C Outputstream out =new FileOutPutStream(“file.txt”);
DataPutputStream out=newDataOutputStream(os);
Out.writerBytes(“hello”)
D Outputstreamout =new OutPutStream(“file.txt”,true);
DataPutputStream out=newDataOutputStream(os);
Out.writerBytes(“hello”)
A 使用默认的文件写入方式,重新写入文件,即清楚已经存在的文件内容 c和a一样;
D中outputstream并没有上述的构造方法
Q 那个类似FilterOutoutStream类的构造器的合法参数
FilterOutoutStream类似BufferOutoutStream类、Dataoutputstrame类和PrintStream
类的父类。哪个类似FileterOutputStream类的合法构造器的合法参数
AinputStream B OutputStream C File D RandomAccessFile E StreamTokenizer

面在Java IO概述的文章中已经提过,JDK1.0中就有的传统的IO包括字节流和字符流。我们这篇就说下java.io中的字节流。说Java
IO字节流也就是InputStream和OutputStream,而从这两个类的继承类层次结构来看,从FilterInputStream和FilterOutputStream开始,上下可分为原始的字节流和“装饰”过的功能封装字节流这篇先说说前半部分——原始字节流的各个类——包括部分源码分析。
0. InputStream和OutputStream
先看下类的声明:
1
2
public abstract class InputStream implements Closeable
public abstract class OutputStream implements Closeable, Flushable
可见此二者都是抽象类,而非接口。也就是说除了分别满足java.io.Closeable和java.io.Flushable,提供了close()和flush()方法的默认实现外,还给出了其它实现,像InputStream就提供了skip()方法实现等。
我们更关心的是InputStream中的几个read()方法和OutputStream的几个write()方法。而实际上最核心的read()和write()方法,InputStream和OutputStream并未给出直接实现,这正是InputStream和OutputStream抽象的地方,我们来看下。
InputStream的read()方法:
§ public abstract int read() throws IOException;核心read()方法,留给子类实现。
§ public int read(byte b[])
§ public int read(byte b[], int off, int len)
后两者是调用第一个方法读特定长度的数据放入byte数组中。
OutputStream的write()方法:
§ public abstract void write(int b) throws IOException;核心write()方法,留给子类实现。
§ public void write(byte b[])
§ public void write(byte b[], int off, int len)
和read()类似,把字节数组中的特定数据挨个调用第一个write()方法写出。
再说read()和wirte()实现,那么就要看一下InputStream和OutputStream的子类。我们先来看看InputStream和OutputStream的直接子类。
在java.io中InputStream的直接子类有:
§ java.io.ByteArrayInputStream
§ java.io.FileInputStream
§ java.io.FilterInputStream
§ java.io.ObjectInputStream
§ java.io.PipedInputStream
§ java.io.SequenceInputStream
§ java.io.StringBufferInputStream
而java.io中OutputStream的直接子类有:
§ java.io.ByteArrayOutputStream
§ java.io.FileOutputStream
§ java.io.FilterOutputStream
§ java.io.ObjectOutputStream
§ java.io.PipedOutputStream
这些当中,FileInputStream和FileOutputStream是与外部IO直接有关系的,而FilterInputStream和FilterOutputStream是“装饰者”设计实现的基类,其它各类都是特定场景下InputStream和OutputStream的实现,我们来具体看看。
1. FileInputStream/FileOutputStream
顾名思义,是文件的输入流和输出流。文件存在于哪里呢?通常存在于外部设备上,这个是这些实现类中比较特殊的。我们如果做过C语言开发,知道我们通常会open操作系统中的文件,并保留其文件描述符fd。其实,在Java中我们也有类似的东西。首先,就有fd属性,它是FileDescriptor类,和C等底层语言中一样,这实际上是对底层文件的一个描述符,和底层文件进行交互的时候少不了它。实际上在FileInputStream/FileOutputStream对象构造方法中,我们初始化了FileDescriptor的fd对象,并调用了open()方法。
遗憾的是,像open()、read()、write()、skip()、available()这些FileInputStream/FileOutputStream中的具体操作方法,在(Sun)JDK中都冠以native,即本地实现,这样做的好处就是上层开发使用者不必关心,统统交由JVM等底层实现进行处理,实现了平台无关性。
在FileInputStream还有这样几个属性:
§ private final FileDescriptor fd;
§ private FileChannel channel = null; JDK1.4之后为了支持NIO的Channel操作
§ private final Object closeLock = new Object(); 关闭时的并发同步锁
§ private volatile boolean closed = false;关闭标志
§ private static final ThreadLocal<Boolean> runningFinalize =

new ThreadLocal<>(); finalize是否运行的标志
此外,再简要看下FileInputStream构造方法的一个具体实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
fd = new FileDescriptor();
fd.incrementAndGetUseCount();
open(name);
}
其它重载要么是调用了这个方法,要么实质上是一致的。FileOutputStream也是类似,出了open()调用的时候有一个append属性参数,标志是否为文件追加。
2. ByteArrayInputStream/ByteArrayOutputStream
名称也很直接,实际上就是字节数组,在构造类对象的时候给出一个byte数组。对于ByteArrayInputStream来说,这个byte数组就是读取的源头,而ByteArrayOutputStream则是write()的目的地。
此外,构造方法中还可以指定这个byte数组的有效起点和长度。
1
2
3
4
5
6
public ByteArrayInputStream(byte buf[], int offset, int length) {
this.buf = buf;
this.pos = offset;
this.count = Math.min(offset + length, buf.length);
this.mark = offset;
}
而对于ByteArrayOutputStream,给出byte数组长度参数即可。甚至还有默认实现,长度32。
1
2
3
4
5
6
7
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ size);
}
buf = new byte[size];
}
3. PipedInputStream/PipedOutputStream
从名字理解也没错,就是管道输入输出(字节)流。它们的存在需要彼此,即PipedInputStream对象和PipedOutputStream对象只有互相存在才真正有意义,当然可以先构建后连接(connect)。
总体来说就是PipedInputStream维护了一个PipedOutputStream对象的属性,而PipedOutputStream也维护了一个PipedInputStream对象属性。而PipedInputStream额外维护了一个缓冲区数组。当PipedOutputStream执行write()的时候,如果PipedInputStream对象未就绪,会发生一个异常。就绪情况下会调用PipedInputStream对象的receive()方法进行接收,也就是写入缓冲数组buf[]。而最终的PipedInputStream的读取就从这个buf[]缓冲数组中来。
4. SequenceInputStream
这个SequenceInputStream是InputStream的另一个实现,而且没有OutputStream与其对应(至少在java.io中没有)。这个类实际上所做的,也是一个对多个其它InputStream的“包装”,而这个所谓的“包装”的作用就是把这些依次(sequently)连接起来,当一个read()到头了(返回-1)就接着读下一个。
下面是read()方法实现:
1
2
3
4
5
6
7
8
9
10
11
public int read() throws IOException {
if (in == null) {
return -1;
}
int c = in.read();
if (c == -1) {
nextStream();
return read();
}
return c;
}
5. StringBufferInputStream
这个类的对象是通过一个String字符串对象来构造,read()实际上就是读取其中的字节(读取到char再和0xFF与操作)。遗憾的是这个类已经被@Deprecated,即不建议使用。不多说了。
6. ObjectInputStream/ObjectOutputStream
ObjectInputStream除了extends了InputStream,还实现了ObjectOutput,ObjectStreamConstants两个接口。ObjectOutputStream也类似。
这两个类与序列化有关,后面序列化文章统一说明。
7. FilterInputStream/FilterOutputStream
从文章开头就提到了,这两个类实际上是Java IO字节流另外一部分的开头,就是以“装饰者模式”实现的,提供了更多功能的封装类别字节流,下篇文章详细介绍整理。
java.io包中的字节流中的类关系有用到GoF《设计模式》中的装饰者模式,而这正体现在FilterInputStream和FilterOutputStream和它的子类上,我们这篇就来看一看。
0. FilterInputStream和FilterOutputStream
首先,这两个都分别是InputStream和OutputStream的子类。而且,FilterInputStream和FilterOutputStream是具体的子类,实现了InputStream和OutputStream这两个抽象类中为给出实现的方法。
但是,FilterInputStream和FilterOutputStream仅仅是“装饰者模式”封装的开始,它们在各个方法中的实现都是最基本的实现,都是基于构造方法中传入参数封装的InputStream和OutputStream的原始对象。
比如,在FilterInputStream类中,封装了这样一个属性:
1
protected volatile InputStream in;
而对应的构造方法是:
1
2
3
protected FilterInputStream(InputStream in) {
this.in = in;
}
read()方法的实现则为:
1
2
3
public int read() throws IOException {
return in.read();
}
其它方法的实现,以及FilterOutputStream也都是同理类似的。
我们注意到FilterInputStream和FilterOutputStream并没给出其它额外的功能实现,只是做了一层简单地封装。那么实现额外功能的实际是FilterInputStream和FilterOutputStream的各个子类。
1. BufferedInputStream/BufferedOutputStream
先说说这个最简单的一对,BufferedInputStream和BufferedOutputStream。顾名思义,Buffered就是缓冲了的。在BufferedInputStream和BufferedOutputStream中,都额外实现了byte数组做buffer。
我们知道在父类FilterInputStream和FilterOutputStream类中,已经在构造方法时封装了原始的InputStream或者OutputStream对象。
在我们使用BufferedInputStream和BufferedOutputStream来进行read()和write()调用的时候,并不一定直接对封装的InputStream或者OutputStream对象进行操作,而是要经过缓冲处理。
在BufferedInputStream的read()中,实际上是一次读取了多个字节到缓冲数组,而非一次只读取一个。后续的read()操作可以直接从数组中获取字节,而不必再次调用封装的InputStream对象的read()操作。这样做其实在一定情况下可以减少底层的read调用次数,降低成本开销,提高了效率。
在BufferedOutputStream中也是一样,它的write()会先把数据写到缓冲数组中,直到数据达到了某个特定的限额,再调用write()的时候回真正调用到封装的OutputStream对象的write()方法。
2. DataInputStream/DataOutputStream
这也是比较重要的一对Filter实现。那么说起功能,实际上就不得不提到他们除了extendsFilterInputStream/FilterOutputStream外,还额外实现了DataInput和DataOutput接口。
我们可以先来看下DataInput和DataOutput这两个interface。

DataInput接口的outline
再看DataOutput:

DataOutput接口的outline
而DataInputStream/DataOutputStream这一对实际上所做的也就是这两个接口所定义的方法。再DataInputStream/DataOutputStream中,这些方法做了拼接和拆分字节的工作。通过这些方法,我们可以方便的读取、写出各种我们实际所面对的类型的数据,而不必具体去在字节层面上做细节操作。
3. PrintStream
这个类不成对,只有这样一个OutputStream。看起名字中的Print,我们会想到什么?println()方法和print()方法。实际上,包括java.lang包中的System.out和System.error,使用的都是PrintStream类对象。
从使用层面来看,这个类主要是提供了丰富的print()和println()的各类参数重载方法。对各个类型的输出,包括换行处理等都集成在内。还有format()方法,帮我们做到了类似C语言中printf()函数的效果。
而从实现上来看,这些print()和println()最终都调用了各类write()方法。在这些write()方法中,实际上使用到了类中封装的这两个属性。
1
2
private BufferedWriter textOut;
private OutputStreamWriter charOut;
他们都是Writer的子类,是字符流处理类,有编码解码机制,我们会在后续文章中详细说明。
4. PushbackInputStream
此类增加了“回退(push back)”功能。在读完一部分数据之后,可以“回退”到之前读过的某个“位置”,并重新设置这些数据。
在实现上,类似于BufferedInputStream,在PushbackInputStream增加了缓冲数组,回退时调整数组的下标索引,并边回退边重置数据。
5. LineNumberInputStream
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: