JAVAIO—字节流

12.3.1  字节流(1)

字节流主要操作byte类型数据,以byte数组为准,主要操作类是OutputStream类和InputStream类。

1.字节输出流:OutputStream

OutputStream是整个IO包中字节输出流的最大父类,此类的定义如下:

 
 
  1. public abstract class OutputStream  
  2. extends Object  
  3. implements Closeable, Flushable 

从以上定义中可以发现,OutputStream类是一个抽象类,如果要使用此类,则首先必须通过子类实例化对象。如果现在要操作的是一个文件,则可以使用FileOutputStream类,通过向上转型后,可以为OutputStream实例化,在OutputStream类中的主要操作方法如表12-3所示。

表12-3  OutputStream类的常用方法

序号

    

类型

    

1

public void close() throws

IOException

普通

关闭输出流

2

public void flush() throws

 IOException

普通

刷新缓冲区

3

public void write(byte[] b)

throws IOException

普通

将一个byte数组写入数据流

4

public void write(byte[]

b,int off,int len) throws 
IOException

普通

将一个指定范围的

byte数组写入数据流

5

public abstract void write(int b)

throws IOException

普通

将一个字节数据写入数据流

此时使用FileOutputStream子类,此类的构造方法如下:

public FileOutputStream(File file) throws FileNotFoundException

操作时必须接收File类的实例,指明要输出的文件路径。

U提示:关于Closeable和Flushable接口的说明。

在OutputStream类的定义中可以发现此类实现了Closeable和Flushable两个接口,那么这两个接口的定义如下。

Closeable接口:

 
 
  1. public interface Closeable{  
  2.     void close() throws IOException  
  3. }  
  4. Flushable接口:  
  5. public interface Flushable{  
  6.     void flush() throws IOException  

这两个接口的作用从其定义方法中可以发现,Closeable表示可关闭,Flushable表示可刷新,而且在OutputStream类中已经有了这两个方法的实现,所以操作时用户一般不会关心这两个接口,而直接使用OutputStream类即可。

范例:向文件中写入字符串

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileOutputStream;  
  4. import java.io.OutputStream;  
  5. public class OutputStreamDemo01 {  
  6.     public static void main(String[] args)  throws Exception {   // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.         File f = new File("d:" + File. separator + "test.txt"); // 声明File  
  10. 对象  
  11.         // 第2步:通过子类实例化父类对象  
  12.         OutputStream out = null;        // 准备好一个输出的对象  
  13.         out = new FileOutputStream(f);  // 通过对象多态性,进行实例化  
  14.         // 第3步:进行写操作  
  15.         String str = "Hello World!!!"// 准备一个字符串  
  16.         byte b[] = str.getBytes();    // 只能输出byte数组,所以将字符串变为  
  17. byte数组  
  18.         out.write(b);                // 将内容输出,保存文件  
  19.         // 第4步:关闭输出流  
  20.         out.close();                // 关闭输出流  
  21.     }  

程序运行结果:


 

12.3.1  字节流(2)

可以发现内容已经成功地写入到文件中,以上程序在实例化、写、关闭时都有异常   发生,为了方便起见,直接在主方法上使用thorws关键字抛出异常,可以减少try…catch语句。

U提示:文件不存在则会自动创建。

在以上操作的test.txt文件,在操作之前本身是不存在的,但是操作之后程序会为用户自动创建新的文件,并将内容写入到文件之中。

以上操作是直接将一个字符串变为byte数组,然后将byte数组直接写入到文件中,当然也可以通过循环把每一个字节一个个地写入到文件之中 。

范例:使用write(int t)的方式写入文件内容

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileOutputStream;  
  4. import java.io.OutputStream;  
  5. public class OutputStreamDemo02 {  
  6.     public static void main(String[] args) 
    throws Exception { // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.         File f = new File("d:" + File.
    separator + 
    "test.txt");// 声明File  
  10. 对象  
  11.         // 第2步:通过子类实例化父类对象  
  12.         OutputStream out = null;        
    // 准备好一个输出的对象  
  13.         out = new FileOutputStream(f);   
    // 通过对象多态性,进行实例化  
  14.         // 第3步:进行写操作  
  15.         String str = "Hello World!!!";  
    // 准备一个字符串  
  16.         byte b[] = str.getBytes();      
    // 只能输出byte数组,所以将字符串变  
  17. byte数组  
  18.         for (int i = 0; i < b.length; i++) {  
  19.             out.write(b[i]);           
    // 将内容输出  
  20.         }  
  21.         // 第4步:关闭输出流  
  22.         out.close();                 
    // 关闭输出流  
  23.     }  

上面程序是将byte数组中的内容一个个地写入到文件之中,实现的功能与上一个程序是一致的。以上两种做法并没有什么不同,两者可以任意使用。

2.追加新内容

之前的所有操作中,如果重新执行程序,则肯定会覆盖文件中的已有内容,那么此时可以通过FileOutputStream向文件中追加内容,FileOutputStream的另外一个构造方法如下:

 
 
  1. public FileOutputStream(File file,boolean 
    append) 
    throws FileNotFoundException 

在构造方法中,如果将append的值设置为true,则表示在文件的末尾追加内容。

范例:修改之前的程序,追加文件内容

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileOutputStream;  
  4. import java.io.OutputStream;  
  5. public class OutputStreamDemo03 {  
  6.     public static void main(String[] args) 
    throws Exception { // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.         File f = new File("d:" + File.separator
    "test.txt");// 声明File  
  10. 对象  
  11.         // 第2步:通过子类实例化父类对象  
  12.         OutputStream out = null;            
    // 准备好一个输出的对象  
  13.         out = new FileOutputStream(f,true);
    // 此处表示在文件末尾追加内容  
  14.         // 第3步:进行写操作  
  15.         String str = "Hello World!!!";    
    // 准备一个字符串  
  16.         byte b[] = str.getBytes();         
    // 只能输出byte数组,所以将字符串变  
  17. byte数组  
  18.         for (int i = 0; i < b.length; i++) {  
  19.             out.write(b[i]);           
    // 将内容输出  
  20.         }  
  21.         // 第4步:关闭输出流  
  22.         out.close();                  
    // 关闭输出流  
  23.     }  

程序运行结果:

可以发现,每次执行后,内容会自动追加到文件的末尾。

提问:如何增加换行?

上面程序确实在文件之后追加内容,可是内容是紧跟在原有内容之后的,如何在文件中增加换行,使文件内容显示更加清晰呢?

回答:使用\r\n增加换行。

如果要换行,则直接在字符串要换行处加入一个"\r\n"。

 
 
  1. // 第3步:进行写操作  
  2. String str = "\r\n Hello World!!!"// 准备一个字符串 

程序运行结果:

 
从结果中发现,新的内容是在换行之后追加的。

12.3.1  字节流(3)

3.字节输入流InputStream

既然程序可以向文件中写入内容,则可以通过InputStream从文件中把内容读取进来。InputStream类的定义如下:

 
 
  1. public abstract class InputStream  
  2. extends Object  
  3. implements Closeable 

与OutputStream类一样,InputStream本身也是一个抽象类,必须依靠其子类,如果现在从文件中读取,子类肯定是FileInputStream。InputStream类中的主要方法如表12-4所示。

表12-4  InputStream类的常用方法

序号

    

类型

    

1

public int available() throws

IOException

普通

可以取得输入文件的大小

2

public void close() throws

 IOException

普通

关闭输入流

3

public abstract int read()

throws IOException

普通

读取内容,

以数字的方式读取

4

public int read(byte[] b) throws

IOException

普通

将内容读到byte数组中,

同时返回读入的个数

FileInputStream类的构造方法如下:

 
 
  1. public FileInputStream(File file)  throws FileNotFoundException 

范例:从文件中读取内容

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileInputStream;  
  4. import java.io.InputStream;  
  5. public class InputStramDemo01 {  
  6.     public static void main(String[] args)  throws Exception { // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.  
  10.         File f = new File("d:" + File.separator + "test.txt"); // 声明File  
  11. 对象  
  12.         // 第2步:通过子类实例化父类对象  
  13.         InputStream input = null;          // 准备好一个输入的对象  
  14.         input = new FileInputStream(f);    // 通过对象多态性进行实例化  
  15.         // 第3步:进行读操作  
  16.         byte b[] = new byte[1024];        // 所有的内容读到此数组中  
  17.         input.read(b);                    // 把内容取出,内容读到byte数组中  
  18.         // 第4步:关闭输入流  
  19.         input.close();                    // 关闭输入流  
  20.         System.out.println("内容为:" +  new String(b)); // 把byte数组变为字符  
  21. 串输出  
  22.     }  

程序运行结果:

内容为:Hello World!!!_

(后面会有大量的空格,此处省略其显示)

内容已经被读取进来,但是发现后面有很多个空格,这是因为开辟的byte数组大小为1024,而实际的内容只有14个字节,也就是说存在1010个空白的空间,在将byte数组变为字符串时也将这1010个无用的空间转为字符串,这样的操作肯定是不合理的。如果要想解决以上的问题,则要观察read方法,在此方法上有一个返回值,此返回值表示向数组中写入了多少个数据。

范例:修正以上的错误

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileInputStream;  
  4. import java.io.InputStream;  
  5. public class InputStreamDemo02 {  
  6.     public static void main(String[] args) throws Exception { // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.         File f = new File("d:" + File. separator + "test.txt");// 声明File  
  10. 对象  
  11.         // 第2步:通过子类实例化父类对象  
  12.         InputStream input = null;           // 准备好一个输入的对象  
  13.         input = new FileInputStream(f);    // 通过对象多态性进行实例化  
  14.         // 第3步:进行读操作  
  15.         byte b[] = new byte[1024];       // 所有的内容读到此数组中  
  16.         int len = input.read(b);        // 将内容读出  
  17.         // 第4步:关闭输入流  
  18.         input.close();                    // 关闭输入流  
  19.         System.out.println("读入数据的长度:" + len);  
  20.         System.out.println("内容为:" +  new String(b, 0, len));// 把byte数组变  
  21. 为字符串输出  
  22.     }  

程序运行结果:

读入数据的长度:14

内容为:Hello World!!!

此时,再次运行程序,发现没有多余的空格产生,这是因为程序在最后只是将byte数组指定范围中的内容变成了字符串。

注意:注意输入文件的路径。

在使用FileInputStream读取时如果指定的路径不存在,则程序运行会出现异常。

12.3.1  字节流(4)

以上问题是否有其他的方式解决,因为虽然最后指定了byte数组的范围,但是程序依然开辟了很多的无用空间,这样肯定会造成资源的浪费,那么此时能否根据文件的数据量来选择开辟空间的大小呢?要想完成这样的操作,则要从File类中着手,因为在File类中存在一个length()的方法,此方法可以取得文件的大小。

范例:开辟指定大小的byte数组

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileInputStream;  
  4. import java.io.InputStream;  
  5. public class InputStreamDemo03 {  
  6.     public static void main(String[] args) 
    throws Exception { // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.         File f = new File("d:" + File.
    separator + 
    "test.txt");// 声明File  
  10. 对象  
  11.         // 第2步:通过子类实例化父类对象  
  12.         InputStream input = null;          
    // 准备好一个输入的对象  
  13.         input = new FileInputStream(f);    
    // 通过对象多态性进行实例化  
  14.         // 第3步:进行读操作  
  15.         byte b[] = new byte[(int)f.length()];  
    // 所有的内容读到此数组中,数组  
  16. 大小由文件决定  
  17.         input.read(b);                   
    // 将内容读出  
  18.         // 第4步:关闭输入流  
  19.         input.close();                
    // 关闭输入流  
  20.         System.out.println("内容为:" + new 
    String(b)); 
    // 把byte数组变为字符  
  21. 串输出  
  22.     }  

程序运行结果:

内容为:Hello World!!!

除以上方式外,也可以通过循环从文件中一个个地把内容读取进来,直接使用read()方法即可。

范例:使用read()通过循环读取

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileInputStream;  
  4. import java.io.InputStream;  
  5. public class InputStreamDemo04 {  
  6.     public static void main(String[] args)
    throws Exception { // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.         File f = new File("d:" + File.
    separator + 
    "test.txt"); //声明File  
  10. 对象  
  11.         // 第2步:通过子类实例化父类对象  
  12.         InputStream input = null;        
    // 准备好一个输入的对象  
  13.         input = new FileInputStream(f);  
    // 通过对象多态性进行实例化  
  14.         // 第3步:进行读操作  
  15.         byte b[] = new byte[(int) f.length()]; 
    // 所有的内容读到此数组中  
  16.         for (int i = 0; i < b.length; i++) {  
  17.             b[i] = (byte)input.read();       
    // 将内容读出  
  18.         }  
  19.         // 第4步:关闭输入流  
  20.         input.close();                    
    // 关闭输入流  
  21.         System.out.println("内容为:" + 
    new String(b)); // 把byte数组变为字符  
  22. 串输出  
  23.     }  

程序运行结果:

内容为:Hello World!!!

但是,以上程序是在明确知道了具体数组大小的前提下开展的,如果此时不知道要输入的内容有多大,则只能通过判断是否读到文件末尾的方式来读取文件。

范例:另一种方式的读取

 
 
  1. package org.lxh.demo12.byteiodemo;  
  2. import java.io.File;  
  3. import java.io.FileInputStream;  
  4. import java.io.InputStream;  
  5. public class InputStreamDemo05 {  
  6.     public static void main(String[] args) 
    throws Exception { // 异常抛出,  
  7. 不处理  
  8.         // 第1步:使用File类找到一个文件  
  9.         File f = new File("d:" + File.separator
    "test.txt"); // 声明File  
  10. 对象  
  11.         // 第2步:通过子类实例化父类对象  
  12.         InputStream input = null;         
    // 准备好一个输入的对象  
  13.         input = new FileInputStream(f);   
    // 通过对象多态性进行实例化  
  14.         // 第3步:进行读操作  
  15.         int len = 0;                     
    // 用于记录读取的数据个数  
  16.         byte b[] = new byte[1024];       
    // 所有的内容读到此数组中  
  17.         int temp = 0;                     
    // 接收读取的每一个内容  
  18.         while ((temp = input.read()) != -1) {  
  19.             // 将每次的读取内容给temp变量,
    如果temp的值不是-1,则表示文件没有读完
     
  20.             b[len] = (byte) temp;  
  21.             len++;  
  22.         }  
  23.         // 第4步:关闭输入流  
  24.         input.close();               
    // 关闭输入流  
  25.         System.out.println("内容为:" +
    new String(b, 0, len));  
  26.     }  

程序运行结果:

内容为:Hello World!!!

以上几种读取字节流的方式,读者最好都掌握,因为随着开发的需要,都有可能使用。

U提示:文件读到末尾了,则返回的内容为-1。

以上程序代码中要判断temp接收到的内容是否是-1,正常情况下是不会返回-1的,只有当输入流的内容已经读到底,才会返回这个数字,通过此数字可以判断输入流中是否还有其他内容。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值