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
如: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.}
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类
其中read()返回的是读入的一个字节所对应的int值(0-255),而)]read(byte[]
b) 和, int, int)]read(byte[]
b, int off, int len) 返回的是读入的字节数
FileOutputStream用于将字节数据写出到文件。继承自OutputStream类
实例代码:使用这两个类进行文件复制:
[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
先看下类的声明:
可见此二者都是抽象类,而非接口。也就是说除了分别满足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构造方法的一个具体实现:
其它重载要么是调用了这个方法,要么实质上是一致的。FileOutputStream也是类似,出了open()调用的时候有一个append属性参数,标志是否为文件追加。
2. ByteArrayInputStream/ByteArrayOutputStream
名称也很直接,实际上就是字节数组,在构造类对象的时候给出一个byte数组。对于ByteArrayInputStream来说,这个byte数组就是读取的源头,而ByteArrayOutputStream则是write()的目的地。
此外,构造方法中还可以指定这个byte数组的有效起点和长度。
而对于ByteArrayOutputStream,给出byte数组长度参数即可。甚至还有默认实现,长度32。
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()方法实现:
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类中,封装了这样一个属性:
而对应的构造方法是:
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()方法中,实际上使用到了类中封装的这两个属性。
他们都是Writer的子类,是字符流处理类,有编码解码机制,我们会在后续文章中详细说明。
4. PushbackInputStream
此类增加了“回退(push back)”功能。在读完一部分数据之后,可以“回退”到之前读过的某个“位置”,并重新设置这些数据。
在实现上,类似于BufferedInputStream,在PushbackInputStream增加了缓冲数组,回退时调整数组的下标索引,并边回退边重置数据。
5. LineNumberInputStream
请选择正确的答案
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 个字节的数据。 |
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 |
我们更关心的是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); } |
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; } |
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]; } |
从名字理解也没错,就是管道输入输出(字节)流。它们的存在需要彼此,即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; } |
这个类的对象是通过一个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; } |
1 2 3 | public int read() throws IOException { return in.read(); } |
我们注意到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; |
4. PushbackInputStream
此类增加了“回退(push back)”功能。在读完一部分数据之后,可以“回退”到之前读过的某个“位置”,并重新设置这些数据。
在实现上,类似于BufferedInputStream,在PushbackInputStream增加了缓冲数组,回退时调整数组的下标索引,并边回退边重置数据。
5. LineNumberInputStream
相关文章推荐
- 【java】面试
- 九月十月百度,迅雷,华为,阿里巴巴笔试面试六十题(第411~470题)
- 一些好的面试题
- iOS面试题答案
- 电话面试1 20160323_1916_18min
- 剑指offer-面试题12:打印1到最大的n位数
- 要想成为优秀的程序员?多阅读是关键
- Java常见面试题汇总(一)
- 程序员与码农的区别
- 程序员修炼之道
- 码农小汪-Hibernate学习1-Start of Hibernate
- 剑指offer-面试题11:数值的整数次方
- 面试总结
- hihocoder之智力竞赛
- 面试宝典
- 某鹅的面试
- day10 面试 重定向和转发的区别
- 【剑指Offer学习】【面试题56:链表中环的入口结点】
- 阿里JAVA开发面试常问问题总结4
- 阿里JAVA开发面试常问问题总结3