黑马程序员之----------java IO流

来源:互联网 发布:顾爷 知乎 编辑:程序博客网 时间:2024/05/14 16:04


------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

-------Java IO-学习笔记--------

1.流的概念

  流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

IO流就是两个对象间的输入,输出操作。

2.   Java I/O主要包括如下几个层次,包含三个部分:

 

   1.流式部分――IO的主体部分;

 

   2.非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;

 

   3.其他类--文件读取部分的与安全相关的类,如:SerializablePermission类,

以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。

 

   主要的类如下:

 

     1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。

 

     2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

 

     3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。

 

     Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。

 

     4. Reader(文件格式操作):抽象类,基于字符的输入操作。

 

     5. Writer(文件格式操作):抽象类,基于字符的输出操作。

 

     6. RandomAccessFile(随机文件操作):它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。

 

 

     Java中IO流的体系结构如图:


 

一、按I/O类型来总体分类:

 

     1. Memory  1)从/向内存数组读写数据: CharArrayReader、 CharArrayWriter、ByteArrayInputStream、ByteArrayOutputStream

2)从/向内存字符串读写数据 StringReader、StringWriter、StringBufferInputStream

      2.Pipe管道  实现管道的输入和输出(进程间通信): PipedReader、PipedWriter、PipedInputStream、PipedOutputStream

      3.File 文件流。对文件进行读、写操作 :FileReader、FileWriter、FileInputStream、FileOutputStream

      4. ObjectSerialization 对象输入、输出 :ObjectInputStream、ObjectOutputStream

      5.DataConversion数据流 按基本数据类型读、写(处理的数据是Java的基本类型(如布尔型,字节,整数和浮点数)):DataInputStream、DataOutputStream

      6.Printing 包含方便的打印方法 :PrintWriter、PrintStream

      7.Buffering缓冲  在读入或写出时,对数据进行缓存,以减少I/O的次数:BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream

      8.Filtering 滤流,在数据进行读或写时进行过滤:FilterReader、FilterWriter、FilterInputStream、FilterOutputStream过

     9.Concatenation合并输入 把多个输入流连接成一个输入流 :SequenceInputStream 

     10.Counting计数  在读入数据时对行记数 :LineNumberReader、LineNumberInputStream

     11.Peeking Ahead 通过缓存机制,进行预读 :PushbackReader、PushbackInputStream

     12.Converting between Bytes and Characters 按照一定的编码/解码标准将字节流转换为字符流,或进行反向转换(Stream到Reader,Writer的转换类):InputStreamReader、OutputStreamWriter

 

分类

字节输入流

字节输出流

字符输入流

字符输出流

抽象基类

InputStream

OutputStream

Reader

Writer

访问文件

FileInputStream

FileOutputStream

FileReader

FileWriter

访问数组

ByteArrayInputStream

ByteArrayOutputStream

CharArrayReader

CharArrayWriter

访问管道

PipedInputStream

PipedOutputStream

PipedReader

PipedWriter

访问字符串

 

 

StringReader

StringWriter

缓冲流

BufferedInputStream

BufferedOutputStream

BufferedReader

BufferedWriter

转换流

 

 

InputStreamReader

OutputStreamWriter

对象流

ObjectInputStream

ObjectOutputStream

 

 

抽象基类

FilterInputStream

FilterOutputStream

FilterReader

FilterWriter

打印流

 

PrintStream

 

PrintWriter

推回输入流

PushbackInputStream

 

PushbackReader

 

特殊流

DataInputStream

DataOutputStream

 

 

 

根据处理数据类型的不同分为:字符流和字节流

  字节流InputStream(读), OutputStream(写)

  字符流Reader(读), Writer(写)

 InputStreamReader 和 OutputStreamWriter 处理字符流和字节流的转换。

 字符流的本质其实就是基于字节流读取时,去查了指定的码表。

字符流和字节流的区别

(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据(文本,字符串)。

 

(3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;

 

(4)字符流在操作的时候是会用到缓冲区的,是通过缓冲区来操作文件

 

结论:优先选用字节流。

只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

按照流的角色分,可以分为节点流和处理流。

可以从、向一个特定的IO设备,读写数据流,称为节点流,节点流常常也被常务低级流(Low Level Stream)

处理流则用于对一个已经存在的流进行连接封装,通过封装后来实现数据的读写功能。处理流称为高级流;

当用处理流的进行输入、输出时,程序并不会直接连接到实际数据源,没有和实际的输入、输出节点连接。使用处理流一个明显的好处是:只要使用相同的处理流,程序就可以采用相同的输入、输出代码来访问不同数据源,随着处理流锁包装节点流的改变,程序实际所访问的数据源也相应发生改变。

处理流的功能主要体现在两个方面:

性能提高:主要以增加缓冲方式来提高输入、输出的效率

操作的便捷: 处理流可能提供了系列便捷的方法来一次性输入、输出大批量的内容,而不是输入、输出一个或多个单位数据

处理流可以“嫁接”在任何已经存在的流的基础上,这就允许Java应用程序采用相同的代码、透明的方式来访问不同的输入、输出设备输入流。

根据数据流向不同分为:输入流和输出流

输入流只能进行读操作(向内存中读数据)

输出流只能进行写操作(向文件中写数据)

 

( 一 )字节流 InputStream/OutputStream 

InputStream 和 OutputStream 是两个抽象类,对于字节为导向的 stream 都扩展这两个基类; 

1、 InputStream 抽象类

  Inputstream类中的常用方法: 

  (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( ) :我们在使用完后,必须对我们打开的流进行关闭. 

InputStream、Reader还支持如下几个方法移动指针:

void mark(int readAheadLimit): 在记录指针当前位置第一个标记(mark)

boolean markSupported(): 判断此输入流是否支持mark()操作,即是否支持记录标记

void reset():将此流的记录的指针重新定位到上一次记录的标记的位置

long skip(long n):记录指针向前移动n个字节、字符

 

主要的子类:

 

   1) FileInputStream把一个文件作为InputStream,实现对文件的读取操作     

    2) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用 

    3) StringBufferInputStream:把一个String对象作为InputStream 

    4) PipedInputStream:实现了pipe的概念,主要在线程中使用 

    5) SequenceInputStream:把多个InputStream合并为一个InputStream 

SequenceInputStream sis = new SequenceInputStream(input1, input2);  

          int temp = 0;  

          while((temp = sis.read()) != -1){  

              output.write(temp);  

          }  

 

00001. ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,

00002. 它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。

00003. PipedInputStream 是从与其它线程共用的管道中读取数据

00004. ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。

00005. 意思是FileInputStream类可以通过一个String路径名创建一个对象,FileInputStream(String name)。

00006. 而DataInputStream必须装饰一个类才能返回一个对象,DataInputStream(InputStream in) 

往文件中写入内容

public class Demo1 {

public static void main(String args[]) throws Exception { // 异常抛出,不处理

// 第1步、使用File类找到一个文件

File f = new File("d:" + File.separator + "test.txt"); // 声明File对象

// 第2步、通过子类实例化父类对象

InputStream input = null// 准备好一个输入的对象

input = new FileInputStream(f); // 通过对象多态性,进行实例化

// 第3步、进行读操作

byte b[] = new byte[1024]; // 所有的内容都读到此数组之中

int len=input.read(b);

input.read(b); // 读取内容

// 第4步、关闭输出流

input.close(); // 关闭输出流

System.out.println("读入长度为:"+len);

System.out.println("内容为:" + new String(b,0,len)); // 把byte数组变为字符串输出

}

}

字节流 读文件内容,节省空间

public class Demo2 {

public static void main(String[] args) throws IOException {

String fileName = "D:" + File.separator + "hello.txt";

File f = new File(fileName);

InputStream in = new FileInputStream(f);

byte[] b = new byte[(int) f.length()];

in.read(b);

//逐个字节读

for (int i = 0; i < b.length; i++) {

   b[i]=(byte)in.read();

}

System.out.println("文件长度为:" + f.length());

in.close();

System.out.println(new String(b));

}

} 

字节流读文件

public class Test{

   public static void main(String[] args) throws IOException {

       String fileName="D:"+File.separator+"hello.txt";

       File f=new File(fileName);

       InputStream in=new FileInputStream(f);

       byte[] b=new byte[1024];

       int count =0;

       int temp=0;

       while((temp=in.read())!=(-1)){

           b[count++]=(byte)temp;

       }

       in.close();

       System.out.println(new String(b));

    }

}

 2.OutputStream 抽象类

  常用方法 

  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( ) : 关闭输出流并释放与流相关的系统资源。 

主要的子类:

 

 

    1) ByteArrayOutputStream:把信息存入内存中的一个缓冲区中 

       2) FileOutputStream:把信息存入文件中 

       3) PipedOutputStream:实现了pipe的概念,主要在线程中使用 

       4) SequenceOutputStream:把多个OutStream合并为一个OutStream 

ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。

PipedOutputStream 是向与其它线程共用的管道中写入数据,

ObjectOutputStream 和所有FilterOutputStream的子类都是装饰流。具体例子跟InputStream是对应的。

流结束的判断:方法read()的返回值为-1时;readLine()的返回值为null时。

字节流案例】向文件中写入字符串

class hello{

   public static void main(String[] args) throws IOException {

       String fileName="D:"+File.separator+"hello.txt";

       File f=new File(fileName);

       OutputStream out =new FileOutputStream(f);

       String str="Hello World";

       byte[] b=str.getBytes();

       out.write(b);

       out.close();

    }

} 

你也可以一个字节一个字节的写入文件:

【案例】逐字节写入文件

class hello{

   public static void main(String[] args) throws IOException {

       String fileName="D:"+File.separator+"hello.txt";

       File f=new File(fileName);

       OutputStream out =new FileOutputStream(f);

       String str="Hello World!!";

       byte[] b=str.getBytes();

       for (int i = 0; i < b.length; i++) {

           out.write(b[i]);

       }

       out.close();

    }

} 

【案例】向文件中追加新内容

class hello{

   public static void main(String[] args) throws IOException {

       String fileName="D:"+File.separator+"hello.txt";

       File f=new File(fileName);

       OutputStream out =new FileOutputStream(f,true);//true表示追加模式,否则为覆盖

       String str="Rollen";

       //String str="\r\nRollen"; 可以换行

       byte[] b=str.getBytes();

       for (int i = 0; i < b.length; i++) {

           out.write(b[i]);

       }

       out.close();

    }

}  

LineNumberInputStream 主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。

PushbackInputStream 的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。

StringBufferInputStream 已经被废弃了,还允许它存在只是为了保持版本的向下兼容而已。

SequenceInputStream 可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO 包中去除,还完全不影响IO 包的结构

PrintStream 主要可以向其他输出流,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例!

【案例】复制文件

class hello{

   public static void main(String[] args) throws IOException {

       if(args.length!=2){

           System.out.println("命令行参数输入有误,请检查");

           System.exit(1);

       }

       File file1=new File(args[0]);

       File file2=new File(args[1]);

         

       if(!file1.exists()){

           System.out.println("被复制的文件不存在");

           System.exit(1);

       }

       InputStream input=new FileInputStream(file1);

       OutputStream output=new FileOutputStream(file2);

       if((input!=null)&&(output!=null)){

           int temp=0;

           while((temp=input.read())!=(-1)){

                output.write(temp);

           }

       }

       input.close();

       output.close();

    }

} 

ByteArrayInputStream案例】使用内存操作流将一个大写字母转化为小写字母

class hello{

   public static void main(String[] args) throws IOException {

       String str="ROLLENHOLT";

       ByteArrayInputStream input=new ByteArrayInputStream(str.getBytes());

       ByteArrayOutputStream output=new ByteArrayOutputStream();

       int temp=0;

       while((temp=input.read())!=-1){

           char ch=(char)temp;

           output.write(Character.toLowerCase(ch));

       }

       String outStr=output.toString();

       input.close();

       output.close();

       System.out.println(outStr);

    }

} 

【DataInputStream案例】 

public class DataOutputStreamDemo{

   public static void main(String[] args) throws IOException{

       File file = new File("d:" + File.separator +"hello.txt");

       DataInputStream input = new DataInputStream(new FileInputStream(file));

       char[] ch = new char[10];

       int count = 0;

       char temp;

       while((temp = input.readChar()) != 'C'){

           ch[count++] = temp;

       }

       System.out.println(ch);

    }

}

【DataOutputStream案例】

public class DataOutputStreamDemo{

   public static void main(String[] args) throws IOException{

       File file = new File("d:" + File.separator +"hello.txt");

       char[] ch = { 'A''B''C' };

       DataOutputStream out = null;

       out = new DataOutputStream(new FileOutputStream(file));

       for(char temp : ch){

           out.writeChar(temp);

       }

       out.close();

    }

} 

【PushBackInputStream案例】回退流操作

public class PushBackInputStreamDemo {

public static void main(String[] args) throws IOException {

String str = "hello,rollenholt";

PushbackInputStream push = null;

ByteArrayInputStream bat = null;

bat = new ByteArrayInputStream(str.getBytes());

push = new PushbackInputStream(bat);

int temp = 0;

while ((temp = push.read()) != -1) {

if (temp == ',') {

push.unread(temp);

temp = push.read();

System.out.print("(回退" + (char) temp + ") ");

else {

System.out.print((char) temp);

}

}

}

}

 

【管道流案例】进程间通信  

class Send implements Runnable{

   private PipedOutputStream out=null;

   public Send() {

       out=new PipedOutputStream();

    }

   public PipedOutputStream getOut(){

       return this.out;

    }

   public void run(){

       String message="hello , Rollen";

       try{

           out.write(message.getBytes());

       }catch (Exception e) {

           e.printStackTrace();

       }try{

           out.close();

       }catch (Exception e) {

           e.printStackTrace();

       }

    }

}

  

class Recive implements Runnable{

   private PipedInputStream input=null;

   public Recive(){

       this.input=new PipedInputStream();

    }

   public PipedInputStream getInput(){

       return this.input;

    }

   public void run(){

       byte[] b=new byte[1000];

       int len=0;

       try{

           len=this.input.read(b);

       }catch (Exception e) {

           e.printStackTrace();

       }try{

           input.close();

       }catch (Exception e) {

           e.printStackTrace();

       }

       System.out.println("接受的内容为 "+(new String(b,0,len)));

    }

}

class hello{

   public static void main(String[] args) throws IOException {

       Send send=new Send();

       Recive recive=new Recive();

        try{

//管道连接

           send.getOut().connect(recive.getInput());

       }catch (Exception e) {

           e.printStackTrace();

       }

       new Thread(send).start();

       new Thread(recive).start();

    }

} 

【ZipOutputStream案例】

文件压缩 ZipOutputStream类 

   ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(  

                 zipFile));  

         zipOut.putNextEntry(new ZipEntry(file.getName()));  

         zipOut.setComment("hello");  

         int temp = 0;  

         while((temp = input.read()) != -1){  

             zipOut.write(temp);  

         } 

ZipOutputStream类的继承关系

java.lang.Object

  |-java.io.OutputStream

|-java.io.FilterOutputStream

|-java.util.zip.DeflaterOutputStream

|-java.util.zip.ZipOutputStream

  

public class ZipOutputStreamDemo1{

   public static void main(String[] args) throws IOException{

       File file = new File("d:" + File.separator +"hello.txt");

       File zipFile = new File("d:" + File.separator +"hello.zip");

       InputStream input = new FileInputStream(file);

       ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(

                zipFile));

       zipOut.putNextEntry(new ZipEntry(file.getName()));

       // 设置注释

       zipOut.setComment("hello");

       int temp = 0;

       while((temp = input.read()) != -1){

           zipOut.write(temp);

       }

       input.close();

       zipOut.close();

    }

} 

压缩多个文件

public class ZipOutputStreamDemo2{

   public static void main(String[] args) throws IOException{

       // 要被压缩的文件夹

       File file = new File("d:" + File.separator +"temp");

       File zipFile = new File("d:" + File.separator + "zipFile.zip");

       InputStream input = null;

       ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(

                zipFile));

       zipOut.setComment("hello");

       if(file.isDirectory()){

           File[] files = file.listFiles();

           for(int i = 0; i < files.length; ++i){

                input = newFileInputStream(files[i]);

                zipOut.putNextEntry(newZipEntry(file.getName()

                        + File.separator +files[i].getName()));

               int temp = 0;

                while((temp = input.read()) !=-1){

                    zipOut.write(temp);

                }

                input.close();

           }

       }

       zipOut.close();

    }

} 

解压缩一个文件

public class ZipFileDemo2{

   public static void main(String[] args) throws IOException{

       File file = new File("d:" + File.separator +"hello.zip");

       File outFile = new File("d:" + File.separator +"unZipFile.txt");

       ZipFile zipFile = new ZipFile(file);

       ZipEntry entry =zipFile.getEntry("hello.txt");

       InputStream input = zipFile.getInputStream(entry);

       OutputStream output = new FileOutputStream(outFile);

       int temp = 0;

       while((temp = input.read()) != -1){

           output.write(temp);

       }

       input.close();

       output.close();

    }

} 

解压缩多个文件

public class ZipFileDemo3{

   public static void main(String[] args) throws IOException{

        File file = new File("d:" +File.separator + "zipFile.zip");

       File outFile = null;

       ZipFile zipFile = new ZipFile(file);

       ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file));

       ZipEntry entry = null;

        InputStream input = null;

       OutputStream output = null;

       while((entry = zipInput.getNextEntry()) != null){

           System.out.println("解压缩" + entry.getName() + "文件");

           outFile = new File("d:" + File.separator + entry.getName());

           if(!outFile.getParentFile().exists()){

               outFile.getParentFile().mkdir();

           }

           if(!outFile.exists()){

                outFile.createNewFile();

           }

           input = zipFile.getInputStream(entry);

           output = new FileOutputStream(outFile);

           int temp = 0;

           while((temp = input.read()) != -1){

                output.write(temp);

           }

           input.close();

           output.close();

       }

    }

} 

 

)字符流 reader/writer

reader抽象类

1.常用方法

(1)  public int read() throws IOException; //读取一个字符,返回值为读取的字符 

(2)  public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/ 

(3)  public abstract int read(char cbuf[],int off,int len) throws IOException; 

/*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/ 

InputStream、Reader还支持如下几个方法移动指针:

void mark(int readAheadLimit): 在记录指针当前位置第一个标记(mark)

boolean markSupported(): 判断此输入流是否支持mark()操作,即是否支持记录标记

void reset():将此流的记录的指针重新定位到上一次记录的标记的位置

long skip(long n):记录指针向前移动n个字节、字符

 

主要子类

 

00001. CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。

00002. PipedReader 是从与其它线程共用的管道中读取数据。

00003. BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。

00004. FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。

00005. InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。

00006. FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。

00007. Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。

 

【案例】以循环方式从文件中读取内容

import java.io.*;

class hello{

   public static void main(String[] args) throws IOException {

       String fileName="D:"+File.separator+"hello.txt";

       File f=new File(fileName);

       char[] ch=new char[100];

       Reader read=new FileReader(f);

       int temp=0;

       int count=0;

       while((temp=read.read())!=(-1)){

           ch[count++]=(char)temp;

       }

       read.close();

       System.out.println("内容为"+new String(ch,0,count));

    }

}

 

2.Writer抽象类

主要方法 

(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

主要子类

 

00001. CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据

00002. Writer out =new FileWriter(f,true);续写文件内容

00003. PipedWriter 是向与其它线程共用的管道中写入数据,

00004. BufferedWriter 是一个装饰器为Writer 提供缓冲功能。

00005. PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。

00006. OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似

 

【FileWriter案例】向文件中写入数据

import java.io.*;

class hello{

   public static void main(String[] args) throws IOException {

       String fileName="D:"+File.separator+"hello.txt";

       File f=new File(fileName);

Writer out =new FileWriter(f);//Writer out =new FileWriter(f,true);续写文件内容

       String str="hello";

       out.write(str);

       out.close();

    }

} 

【案例】Scanner类从文件中读出内容

import java.io.File;

import java.io.FileNotFoundException;

import java.util.Scanner;

public class ScannerDemo{

   public static void main(String[] args){

  

       File file = new File("d:" + File.separator +"hello.txt");

       Scanner sca = null;

       try{

           sca = new Scanner(file);

       }catch(FileNotFoundException e){

           e.printStackTrace();

       }

       String str = sca.next();

       System.out.println("从文件中读取的内容是:" + str);

    }

}

 

6.字符流的输入与输出的对应


字符流的缓冲区:

       为什么要缓冲区:提高对流的操作效率

       原理:其实就是对数组进行封装

对应的对象:

BufferedWriter

 特有方法: newline():跨平台的换行符

BufferedReader

 特有方法: ReadLine():一次读一行,到行标记时,将行标之前的字符数据作为字符型返回。读到末尾时,返回null。

在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在,因此在建立缓冲区对象时,要先有流对象存在。

其实缓冲内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储。为了提高操作数据的效率。

      

//建立缓冲区对象必须把流对象作为参数传递给缓冲区的构造方法。

public class Test {

public static void main(String[] args) throws IOException {

BufferedWriter Bufw = new BufferedWriter(new FileWriter("Demo.txt"));

Bufw.write("abcdefg");// 将数据写入缓冲区

Bufw.flush(); // 对缓冲区的数据进行刷新,将数据刷到目的地中。

Bufw.close(); // 关闭缓冲区,其实关闭的是被包装在内部的流对象。

 

// 读取缓冲对象

BufferedReader bufr = new BufferedReader(new FileReader("Demo.txt"));

String line = null;

// 按照行的形式取出数据。取出的每一行数据不包含回车符。

while ((line = bufr.readLine()) != null) {

System.out.println(line);

}

bufr.close();

}

}例:通过缓冲区的形式,对文本文件进行拷贝

public class Test{

public static void main (String[] args) throws IOException {

BufferedReader bufr = new BufferedReader(new FileReader("Demo.txt"));

BufferedWriter bufw = new BufferedWriter(new FileWriter("mo.txt")); 

String line = null;

while ((line = bufr.readLine()) != null){

bufw.write(line);

bufw.newLine();

bufw.flush();

bufw.close();

bufr.close();

}

}

}

7.字符流与字节流转换 

 

InputStreamReader : 把一个以字节为导向的 stream 转换成一个以字符为导向的 stream 。 

InputStreamReader 类是从字节流到字符流的桥梁:它读入字节,并根据指定的编码方式,将之转换为字符流。 

 

InputStreamReader 的 read() 方法之一的每次调用,可能促使从基本字节输入流中读取一个或多个字节。 

InputStreamReader(InputStream) 用缺省的字符编码方式,创建一个 InputStreamReader 。 

InputStreamReader(InputStream, String) 用已命名的字符编码方式,创建一个 InputStreamReader 。 

 

Writer out=new OutputStreamWriter(new FileOutputStream(file));  //将输出的字符流转化为字节流 

 

Reader read=new InputStreamReader(new FileInputStream(file));  

  char[] b=new char[100];  

          int len=read.read(b); 

为了达到更高效率,考虑用 BufferedReader 封装 InputStreamReader , 

BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

public class BufferedReaderDemo{

   public static void main(String[] args){

       BufferedReader buf = new BufferedReader(

                newInputStreamReader(System.in));

       String str = null;

       System.out.println("请输入内容");

       try{

           str = buf.readLine();

       }catch(IOException e){

           e.printStackTrace();

       }

       System.out.println("你输入的内容是:" + str);

    }

} 

 

OutputStreamWriter 将多个字符写入到一个输出流,根据指定的字符编码将多个字符转换为字节。 

每个 OutputStreamWriter 合并它自己的 CharToByteConverter, 因而是从字符流到字节流的桥梁。

【案例】将字节输入流转换为字符输入流

import java.io.*;

class hello{

   public static void main(String[] args) throws IOException {

       String fileName= "d:"+File.separator+"hello.txt";

       File file=new File(fileName);

       Reader read=new InputStreamReader(new FileInputStream(file));

       char[] b=new char[100];

       int len=read.read(b);

       System.out.println(new String(b,0,len));

       read.close();

    }

} 

【案例】将字节输出流转化为字符输出流

import java.io.*;

class hello{

   public static void main(String[] args) throws IOException {

       String fileName= "d:"+File.separator+"hello.txt";

       File file=new File(fileName);

       Writer out=new OutputStreamWriter(new FileOutputStream(file));

       out.write("hello");

       out.close();

    }

} 

 

 

8.转换流的特点:

00001. 其是字符流和字节流之间的桥梁

00002. 可对读取到的字节数据经过指定编码转换成字符

00003. 可对读取到的字符数据经过指定编码转换成字节

何时使用转换流?

00001. 当字节和字符之间有转换动作时;

00002. 流操作的数据需要编码或解码时。

具体的对象体现:

00001. InputStreamReader:字节到字符的桥梁

00002. OutputStreamWriter:字符到字节的桥梁

这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

 

推回输入流PushbackInputStream、PushbackReader

常用方法:

void unread(byte[]/char[] buf):将一个字节/字符数组推到缓冲区里,运行重复读取推回的内容

void unread(byte[]/char[] buf, int off, int len):将一个字节/字符数组从off位置开始读取,长度是len的字符/字节数组的内容推回到缓冲区中,允许重复刚才读取的内容

void unread(int b):将一个字节、字符推回到缓冲区

这2个推回输入流都带一个缓冲区,当程序调用unread的时候,系统就会把指定数组的内容推回到缓冲区,而推回输入流每次调用read的方法,总会先去读取推回缓冲区中的内容,只有完全读取的缓冲区里面的内容后,而且还没有装满read所需的数组,才会到原输入流中读取内容;

5、序列化

在远程调用、分布式开发中常用到序列化,将java对象序列化的文件中保存,然后在解析的时候又反序列化,其中需要用到Serializable接口;在实现了该接口的对象可以顺利序列化成一个文件保存在硬盘上,反序列化也是通过该接口的id来查找该对象的。

transient可以忽略对象中某个属性不被序列化。

总结:

 

一、字符流
基类:Reader(读)、Writer(写)
|-Reader
   |--BufferedReader:对Reader进行了包装,提供了缓冲区,有readLIne方法
   |     构造函数:BufferedReader(Reader r)
   |--InputStreamReader:转换流,将字节流转成字符流new InputStreamReader(InputStream in)
       |---FileReader:读取文件的字符流,FileReader(File file),FileReader(String fileName)
|-Writer
   |--BufferedWriter:包装类,常用方法:write(String s)、flush、newLine(),
      BufferedWriter(Writer w)
   |--OutputStreamWriter:转换流,OutputStreamWriter(OutputStream out)
       |---FileWriter:写入文件,FileWriter(File file),FileWriter(String fileName)
        FileWriter(File file,boolean append),FileWriter(String fileName,boolean append)
        当append值为true时,将写入文件的末尾处,当为False时,从文件开头开始写,就会覆盖原来的。
       
二、字节流
|-InputStream(输入流)
   |--FileInputStream:读取文件的字节流,和FIleReader用法基本一样。
   |--FilterInputStream:过滤流,一般不使用,只是对InputStream的简单包装
       |---BufferedInputStream:包装类,BufferedInputSteam(InputStream in),提供了缓冲区
|-OutputStream(输出流)
   |--FileOutputStream
   |--FilterOutputStream
       |---BufferedOutputStream
      
、使用IO流必须要捕获异常,原因在于我们必须要还资源(关闭流)。
FileWriter fw = null;
try{
fw = new FileWriter(new File());
fw.write("a");
}
catch(IOException e)
{
e.printStackTrace();//异常类名、异常信息、详细错误信息
System.out.println(e.toString());//异常类名、异常信息
System.out.println(e.getMessage());//异常信息
}
finally
{
try{if(fw!=null)fw.close();}catch(IOException e){e.printStackTrace();}
}


Java IO 的一般使用原则 :  

一、按数据来源(去向)分类: 

1 、是文件: FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 ) 

2 、是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字节流 ) 

对Byte数组进行读写的字节流,针对内存进行读写源和目的地都是内存,一般用于对内存中的数据进行处理。

3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符流 ) 

4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 ) 

5 、网络数据流: InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 ) 

二、按是否格式化输出分: 

1 、要格式化输出: PrintStream, PrintWriter 打印流
有一个特殊的方法print可以实现打印

write方法是直接将字节和字符写出去
print:首先调用对象的toString方法转成字符串(如果是基本数据类型,会先自动装箱)
再将字符串编码成字节数组,调用write方法写出去

 

三、按是否要缓冲分: 

1 、要缓冲: BufferedInputStream, BufferedOutputStream,( 字节流 ) BufferedReader, BufferedWriter( 字符流 ) 

四、按数据格式分: 

1 、二进制格式(只要不能确定是纯文本的) : InputStream, OutputStream 及其所有带 Stream 结束的子类 

2 、纯文本格式(含纯英文与汉字或其他编码方式); Reader, Writer 及其所有带 Reader, Writer 的子类 

五、按输入输出分: 

1 、输入: Reader, InputStream 类型的子类 

2 、输出: Writer, OutputStream 类型的子类 

六、特殊需要: 

1 、从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter 

2 、对象输入输出: ObjectInputStream, ObjectOutputStream 

使用writeObject方法写入的对象,只能由readObject方法读出来操作的对象必须实现java.io.Serializable

序列化接口,该对象才可以被序列化和反序列化。

 

3 、进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter 

构造方法:PipedInputStream(PipedOutputStream pos)实现拼接也可以通过connect(PipedOutputStream pos)方法进行拼接

 

4 ,DataInputStream、DataOutputStream操作基本数据类型,格式化数据readInt、writeInt等方法。
writeInt写入一个整数,文件大小为4字节。证明就是把基本数据类型对应的字节写出去了,没有丢失精度

5,SequenceInputStream序列流,可以将多个字节流组合起来
构造方法:SequenceInputStream(Enumeration<? extends InputStream> e)
//Enumeration可以通过Vector来获得,如果用的是ArrayList,如何获得呢?
   SequenceInputStream(InputStream in1,InputStream in2)

 

 

1、不管是输入还是输出流,使用完毕后要close(),如果是带有缓冲区的输出流,应在关闭前调用flush()。

 

2、应该尽可能使用缓冲区,来减少IO次数,以提高性能。

 

3、能用字符流处理的不用字节流。

 

 

Java IO流的高级概念

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStream;

 

public class 编码 {

 public static void main(String[] args)throws IOException{

 File file = new File("d:" + File.separator + "hello.txt");

        OutputStream out = new FileOutputStream(file);

        byte[] bytes = "你好".getBytes("ISO8859-1");

        out.write(bytes);

        out.close();

        //输出结果为乱码,系统默认编码为GBK,而此处编码为ISO8859-1 

        System.out.println("系统默认编码为:"+ System.getProperty("file.encoding"));

    }

}

 

对象的序列化

对象序列化就是把一个对象变为二进制数据流的一种方法。

一个类要想被序列化,就行必须实现Serializable接口。

实现了这个接口之后,就表示这个类具有被序列化的能力。

 

  实现具有序列化能力的类

 

public class Person implements Serializable {

private String name;

private int age;

 

public Person() {

}

 

Person(String name, int age) {

this.name = name;

this.age = age;

}

 

public String toString() {

return "姓名:" + name + "  年龄:" + age;

}

}

 

 序列化一个对象FileOutputStream

public class ObjectOutputStreamDemo {

 public static void main(String[] args) throws IOException{

        File file = new File("d:" + File.separator + "hello.txt");

        ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream(file));

        oos.writeObject(new Person("rollen", 20));

        oos.close();    

}

}

 

 

 对象的反序列化 ObjectInputStream

public class ObjectInputStreamDemo {

public static void main(String[] args) throws Exception {

File file = new File("d:" + File.separator + "hello.txt");

ObjectInputStream input = new ObjectInputStream(new FileInputStream(file));

Object obj = input.readObject();

input.close();

System.out.println(obj);

}

}

 

注意:被Serializable接口声明的类的对象的属性都将被序列化,但是如果想自定义序列化的内容的时候,就需要实现Externalizable接口。

当一个类要使用Externalizable这个接口的时候,这个类中必须要有一个无参的构造函数,如果没有的话,在构造的时候会产生异常,这是因为在反序列话的时候会默认调用无参的构造函数。

  

使用Externalizable来定制序列化和反序列化操作

 

 

class Person implements Externalizable{

private String name;

private int age;

    public Person(){

  

    }

  

    public Person(String name,int age){

        this.name = name;

        this.age = age;

    }

  

    public String toString(){

        return "姓名:" +name + "  年龄:" +age;

    }

  

    // 复写这个方法,根据需要可以保存的属性或者具体内容,在序列化的时候使用

  

    public void writeExternal(ObjectOutput out) throws IOException{

       out.writeObject(this.name);

        out.writeInt(age);

    }

  

    // 复写这个方法,根据需要读取内容 反序列话的时候需要

    public void readExternal (ObjectInput in) throws IOException,ClassNotFoundException{

        this.name = (String)in.readObject();

        this.age =in.readInt();

    }

}

 

public class ExternalizableDemo {

public static void main(String[] args) throws Exception{

        ser(); // 序列化

        dser(); // 反序列话

    }

  

    public static void ser()throws Exception{

        File file = new File("d:" + File.separator + "hello.txt");

        ObjectOutputStream out= new ObjectOutputStream(new FileOutputStream(

                file));

        out.writeObject(new Person("rollen", 20));

        out.close();

    }

  

    public static void dser()throws Exception{

        File file = new File("d:" + File.separator + "hello.txt");

        ObjectInputStream input = new ObjectInputStream(new FileInputStream(

                file));

        Object obj =input.readObject();

        input.close();

       System.out.println(obj);

    }

}

  

 

注意:当我们使用Serializable接口实现序列化操作的时候,如果一个对象的某一个属性不想被序列化保存下来,那么我们可以使用transient关键字进行说明:

 

序列化和反序列化的操作 transient 实现对象的部分属性

 

public class serDemo {

public static void main(String[] args) throws Exception {

ser(); // 序列化

dser(); // 反序列话

}

 

public static void ser() throws Exception {

File file = new File("d:" + File.separator + "hello.txt");

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(

file));

out.writeObject(new Person1("rollen", 20));

out.close();

}

 

public static void dser() throws Exception {

File file = new File("d:" + File.separator + "hello.txt");

ObjectInputStream input = new ObjectInputStream(new FileInputStream(

file));

Object obj = input.readObject();

input.close();

System.out.println(obj);

}

}

 

class Person1 implements Serializable {

// 注意这里

private transient String name;

private int age;

 

public Person1() {

 

}

 

public Person1(String name, int age) {

this.name = name;

this.age = age;

}

 

public String toString() {

return "姓名:" + name + "  年龄:" + age;

}

}

 

 序列化一组对象

 

public class 序列化一组对象 {

 

public static void main(String[] args) throws Exception {

Person per[] = { new Person("张三", 30), new Person("李四", 31),

new Person("王五", 32) };

// 定义对象数组

ser(per);

// 序列化对象数组

Object o[] = dser();

// 读取被序列化的对象数组

for (int i = 0; i < o.length; i++) {

Person p = (Person) o[i];

System.out.println(p);

}

}

 

public static void ser(Object obj[]) throws Exception {

File f = new File("D:" + File.separator + "tt.txt");

ObjectOutputStream oos = null;

OutputStream out = new FileOutputStream(f); // 文件输出流

oos = new ObjectOutputStream(out);

// 为对象输出流实例化

oos.writeObject(obj);

// 保存对象数组到文件

oos.close();

// 关闭输出

}

 

public static Object[] dser() throws Exception {

File f = new File("D:" + File.separator + "tt.txt");

ObjectInputStream ois = null;

InputStream input = new FileInputStream(f);

// 文件输入流

ois = new ObjectInputStream(input);

// 为对象输出流实例化

Object obj[] = (Object[]) ois.readObject();

// 读取对象数组

ois.close();

// 关闭输出

return obj;

}

}

 

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

0 0
原创粉丝点击