java之I/O输入输出流解析

时间:2023-02-26 16:48:01

一、流的概述

流是一组有序的数据序列,根据操作的类型,可以分为输入流和输出流。I/O流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。


二、输入模式 输出模式图

java之I/O输入输出流解析


三、java流的分类

按流向分:

输入流: 程序可以从中读取数据的流。

输出流: 程序能向其中写入数据的流。

按数据传输单位分:

字节流: 以字节为单位传输数据的流

字符流: 以字符为单位传输数据的流

按功能分:

节点流: 用于直接操作目标设备的流

处理流: 是对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能。

四、字节输入流(InputStream)/字节输出流(OutputStream)简介及方法

InputStream类是字节输入流的抽象类,是所有字节输入流的父类。必须依靠其子类实现各种功能,且数据单位为字节(8bit);他是指数据以字节形式从其他文件或者设备向程序流入。常用方法如下:

       (1) public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。

  (2) public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的 

  (3) public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。 

  (4) public int available( ):返回输入流中可以读取的字节数。注意:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返                   回0,这个方法必须由继承InputStream类的子类对象调用才有用, 

  (5) public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取 

  (6) public int close( ) :我们在使用完后,必须对我们打开的流进行关闭. 


java之I/O输入输出流解析

OutputStream类是字节输出流的抽象类,此抽象类是表示输出字节流的所有类的超类;他是数据以字节形式从程序流出,输出流只能向流中写入数据

OutputStream提供了3个write方法来做数据的输出,这个是和InputStream是相对应的。 

  1. public void write(byte b[ ]):将参数b中的字节写到输出流。 

  2. public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。 

  3. public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。 

  4. public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。 

  5. public void close( ) : 关闭输出流并释放与流相关的系统资源。 


注意:并不是所有的inputstream类的子类都支持inputstream中定义的方法,如skip() mark() reset()等方法只对某些子类有用

java之I/O输入输出流解析

五、文件输入/输出流实例


FileInputStream类与FileOutputStream类

<span style="font-size:12px;">/*文件输入流: FileInputStream类
作用:以文件作为数据输入源的数据流。或者说是打开文件,从文件读数据到内存的类。
*/
import java.io.IOException;
import java.io.FileInputStream;
;
public class TestFile {
public static void main(String args[]) throws IOException {
try{
FileInputStream rf=new FileInputStream("A.java"); //有内容的java文件
int n=512; byte b[]=new byte[n];
while((rf.read(b,0,n)!=-1)&&(n>0)){
System.out.println(new String(b) );
}
System.out.println();
rf.close();
} catch(IOException IOe){
System.out.println(IOe.toString());
}

}

}

/*文件输出流:FileOutputStream类
作用:用来处理以文件作为数据输出目的数据流;或者说是从内存区读数据入文件
*/
import java.io.IOException;
import java.io.FileOutputStream;
public class TestFile {
public static void main(String args[]) throws IOException {
try {
System.out.println("请输入");
int count, n = 512;
byte buffer[] = new byte[n];
count = System.in.read(buffer); //从键盘接收
FileOutputStream wf = new FileOutputStream("d:/write.txt"); //文件需要已存在
wf.write(buffer, 0, count);
wf.close(); // 当流写操作结束时,调用close方法关闭流。
System.out.println("内容保存成功!");
} catch (IOException IOe) {
System.out.println("文件写入失败!");
}
}

}</span>


六、字符流的读取和写入 抽象类:Reader和Writer

Reader用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。

  1) FileReader :与FileInputStream对应  

               主要用来读取字符文件,使用缺省的字符编码,有三种构造函数: 

      (1)将文件名作为字符串 :FileReader f=new FileReader(“c:/temp.txt”); 

      (2)构造函数将File对象作为其参数。 

              File f=new file(“c:/temp.txt”); 

              FileReader f1=new FileReader(f); 

      (3)  构造函数将FileDescriptor对象作为参数 

              FileDescriptor() fd=new FileDescriptor() 

              FileReader f2=new FileReader(fd); 

主要方法

           (1) 用指定字符数组作为参数:CharArrayReader(char[]) 

           (2) 将字符数组作为输入流:CharArrayReader(char[], int, int) 

              读取字符串,构造函数如下: public StringReader(String s); 

           (3) CharArrayReader:与ByteArrayInputStream对应  

      (4) StringReader : 与StringBufferInputStream对应 

      (5) InputStreamReader从输入流读取字节,在将它们转换成字符:Public inputstreamReader(inputstream is); 

      (6) FilterReader: 允许过滤字符流   protected filterReader(Reader r); 

      (7) BufferReader :接受Reader对象作为参数,并对其添加字符缓冲器,使用readline()方法可以读取一行。   Public BufferReader(Reader r); 

java之I/O输入输出流解析

Writer 写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。

       1) FileWrite: 与FileOutputStream对应  

        将字符类型数据写入文件,使用缺省字符编码和缓冲器大小。 

        Public FileWrite(file f); 

   2)  chararrayWrite:与ByteArrayOutputStream对应 ,将字符缓冲器用作输出。 

      Public CharArrayWrite(); 

  3) PrintWrite:生成格式化输出 

      public PrintWriter(outputstream os); 

  4) filterWriter:用于写入过滤字符流 

      protected FilterWriter(Writer w); 

  5) PipedWriter:与PipedOutputStream对应   

       6) StringWriter:无与之对应的以字节为导向的stream  

 主要方法:

      (1)  public void write(int c) throws IOException; //将整型值c的低16位写入输出流 

  (2)  public void write(char cbuf[]) throws IOException; //将字符数组cbuf[]写入输出流 

  (3)  public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流 

  (4)  public void write(String str) throws IOException; //将字符串str中的字符写入输出流 

  (5)  public void write(String str,int off,int len) throws IOException; //将字符串str 中从索引off开始处的len个字符写入输出流 

  (6)  flush( ) //刷空输出流,并输出所有被缓存的字节。 

  (7)  close()    关闭流 public abstract void close() throws IOException

java之I/O输入输出流解析

----------------------------------------------------------------------------------------------------------------------------
字节与字符的转换流

说到这先说一下二者的区别

       1)字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,

       2)而字节流处理单元为1个字节, 操作字节和字节数组。

       字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。

      所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好! 
        如果是 音频文件、图片、歌曲,就用字节流好点。

        如果是关系到中文(文本)的,用字符流好点

InputStreamReader 和OutputStreamWriter 分别是Reander和Writer的子类,二者用于字节流和字符流之间的转换。

InputStreamReader用于将输入的字节流转变为字符流

OutputStreamWriter  用于将输入的字符流转变为字节流

Reader reader = new InputStreamReader(new FileInputStream("d:\\1.txt"));
System.out.println(reader.read());
reader.close();

File f=new File(“d:/1.txt”);
OutputStreamWriter os=new OutputStreamWriter(new FileOPutInStream(f));
Os.write(“hello word”);
Os.close();
 


---------------------------------------------------------------------------------------------------------------

七、带缓存的输入/输出流

BufferedInputStream:当向缓冲流写入数据时候,数据先写到缓冲区,待缓冲区写满后,系统一次性将数据发送给输出设备。

BufferedOutputStream :当从向缓冲流读取数据时候,系统先从缓冲区读出数据,待缓冲区为空时,系统再从输入设备读取数据到缓冲区。

1)将文件读入内存:

将BufferedInputStream与FileInputStream相接

  FileInputStream in=new  FileInputStream( “file1.txt ” );

  BufferedInputStream bin=new  BufferedInputStream( in); 

2)将内存写入文件:

将BufferedOutputStream与 FileOutputStream相接

FileOutputStreamout=new FileOutputStream(“file1.txt”);

BufferedOutputStream  bin=new BufferedInputStream(out);

BufferedReader和BufferedWriter是带缓冲区的Reader和Writer.

使用BufferedReader读取文本时,将首先从文件中读取字符数据并存入缓冲区中,然后调用read(),先冲缓冲区开始读取,缓冲区不足是再从文件中读取;

使用BufferedWriter时,写入数据将先存储到缓冲区中,在缓冲区饱满的情况下将一次性写入目的地。

通过缓冲区可以减少对硬盘的输入或输出操作,提高文件存取效率。

File f=new File(“d;/demo.txt);
FileWriter bufWriter=new BufferedWriter(writer);
bufWriter.writer(“hello word);
bufwruter.close();
writer.close();
FileReader reader =new FileReader(“f);
BufferedReader bufReader=new BufferedReader(reader);
Sysout.out.print(bufReader.readLine());


八、数据输入/输出流

DataInputStream与DataOutputStream允许应用程序以与机器无关的方式从底层输入流中读取基本java数据类型。

简单说就是,当读取一个数据时,不必再关心这个数值应当是哪种字节

构造方法

DataInputStream(InputStream in)  使用指定的底层 InputStream 创建一个 DataInputStream

DataOutputStream(OutputStream out) 创建一个新的数据输出流,将数据写入指定基础输出流。

DataOutputStream类提供的3种写入方法

writeBytes(String s)  将字符串按字节顺序写出到基础输出流中。

writeChars(String s)   将字符串按字符顺序写入基础输出流。

writeUTF(String str)  以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。

<span style="font-size:12px;">public static void main(String[] args) throws Exception {
//创建FileOutputStream对象
FileOutputStream fos=new FileOutputStream("d:/1.txt");
//创建DataOutputStream对象
DataOutputStream dos=new DataOutputStream(fos);
//写入磁盘文件数据
dos.writeUTF("使用writeUTF()方法写入数据");
// dos.writeBytes("使用writeBytes()方法写入数据");
// dos.writeChars("使用writeChars()方法写入数据");
dos.close();//关闭流
//创建FileInputStream对象
FileInputStream fis=new FileInputStream("d:/1.txt");
//创建DataInputStream对象
DataInputStream dis=new DataInputStream(fis);
System.out.print(dis.readUTF()); //将文件输入输出

}
}</span>

九、一言不合就上题:文件及文件夹的拷贝实例


<span style="font-size:12px;">public static void main(String[] args) {
File f=new File("d:/英雄时刻");
new File(f, f.getName()).mkdir();
copyDirectory(new File("d:/英雄时刻"),new File( "e:/"));
try {
copyFile(new File("d:/1.txt"), new File("e:/1.txt"));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("拷贝完毕!");
}
//文件的复制
public static void copyFile(File f1,File f2) throws IOException{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(f1));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(f2));
byte [] b=new byte[512];
int len;
while((len=bis.read(b))!=-1){
bos.write(b, 0, len);
}
bos.flush();
if(bos!=null)
bos.close();
if(bos!=null)
bis.close();

}
//文件夹的复制
public static void copyDirectory(File f1,File f2){
File f=new File(f2, f1.getName());
f.mkdir();
File []fl=f1.listFiles();
for (File file : fl) {
if(file.isDirectory()){
copyDirectory(file, f);
}
else{
try {
copyFile(file, new File(f,file.getName()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}</span>

十、IOException异常类的子类

1.public class  EOFException :
   非正常到达文件尾或输入流尾时,抛出这种类型的异常。

2.public class FileNotFoundException:
   当文件找不到时,抛出的异常。

3.public class InterruptedIOException:
   当I/O操作被中断时,抛出这种类型的异常。






为什么要有异常处理
因为在输入输出中,会出现一些你想不到的异常,所以要用try catch语句捕获这些异常并做友好提示,方便我们的操作
比如读文件时你的文件不存在 它会出现系统错误,为了方便,捕获他做友好提示很方便继续操作

更多内容:
http://blog.csdn.net/hguisu/article/details/7418161
http://blog.csdn.net/xfhuajian/article/details/6439374