Java字节流和字符流(超鸡简单明了的!!!)

字节流和字符流

1流操作简介

File类不支持文件内容处理,如果要处理文件内容,必须要通过流的操作模式来完成。流分为输入流和输出流。在java.io包中,流分为两种:字节流与字符流
字节流(byte):(针对字节的处理,比较底层)InputStream、OutputStream
字符流(char):(针对于字符的处理)Reader、Writer
字节流与字符流的区别只有一个,字节流是原生操作,字符流是处理后的操作。
在进行网络数据传输,磁盘数据保存所保存所支持的数据类型只有:字节。
而所有磁盘中的数据必须先读取到内存后才能进行操作,而内存中会帮助我们把字节变为字符。字符更加适合处理中文。

流操作流程:
无论是字符流还是字节流,操作流程几乎一样,以文件操作为例

    1:取得File对象
    2:取得file对象的输入、输出流
    3:进行数据的读取或写入操作
    4:关闭流(close()).

IO处理属于资源操作,所有资源处理(IO、数据库、网络)使用后都必须关闭。

2、字节输出流(OutputStream)

如果要想通过程序进行内容输出,则可以使用java.io.OutoutStream
来观察OutputStream类的定义结构

public abstract class OutputStream implements Closeable,Flushable

OutputStream类实现了Closeable、Flushable两个接口,这两个接口中的方法:

Closeable:public void close() throws IOException;
Flushable:public void flush() throws IOException;

在OutputStream类中还定义有其他方法:

将指定的字节数组全部输出:public void write(byte[] b)throws IOException;
将部分字节数组输出:public void write(byte[] ,int offset,int len)throws IOException;
输出单个字节:public abstract void write(int b)throws IOException;

由于OutputStream是一个抽象类,所以要想为父类实例化,就必须使用子类。由于方法名称都由父类声明好了,所以我们在此处只需要关心子类的构造方法。如果要进行文件的操作,可以使用FileOutputStream类来处理。这个类的构造方法如下:

文件内容覆盖:public FileOutputStream(File file)throws FileNotFoundException ;
文件内容追加:public FileOutputStream(File file,boolean append);

实现文件的内容输出:

//实现我们文件内容的输出
import java.io.*;

public class OutputStreamTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白乐荣"+
                File.separator+"Desktop"+File.separator+"Tset.txt");
       //如果文件不存在就创建
        if(!file.getParentFile().exists()){//必须保证父目录存在
            file.getParentFile().mkdirs();//创建多级目录
        }
        //OutputStream是一个抽象类,所以需要通过子类进行实例话,此时自能操作File类
        OutputStream outputStream=new FileOutputStream(file);
        //要求输入到文件的内容
        String msg="我爱编程,我爱java";

        //将内容变为字节数组
        outputStream.write(msg.getBytes());
        //关闭输出
        outputStream.close();
    }
}

执行上面的代码,你将会发现桌面上出现了一个Tset.txt文件,里面的内容就是我爱编程,我爱Java。
在进行我们文件输出的时候,所有的文件会自动帮助用户创建,不需要调用createFile()手工创建。这个程序如果重复执行,并不会出现追加的情况而是一直覆盖,如果需要文件内容追加,则需要调用FileOutputStream提供的另外一种构造方法。
实现我们的文件内容的追加

//实现我们的追加程序
 import java.io.*;

public class FileAddTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白乐荣"+
                File.separator+"Desktop"+File.separator+"Tset.txt");
        //如果文件不存在就创建
        if(!file.getParentFile().exists()){//必须保证父目录存在
            file.getParentFile().mkdirs();//创建多级目录
        }
        //OutputStream是一个抽象类,所以需要通过子类进行实例化,此时只能操作File类
        OutputStream outputStream=new FileOutputStream(file,true);
        //要求输出到文件的内容
        String msg="我爱我自己";
        //将内容变为字节数组
        outputStream.write(msg.getBytes());
        //关闭输出
        outputStream.close();
    }
}

我们将上述代码执行几遍,就会出现几次我们的“我爱我自己”。
这就是我们的文件内容追加。
接下来,我们在实现一个文件部分内容输出的代码

部分输出有时会产生乱码

AutoCloseable的自动关闭支持

从JDK1.7开始追加一个AutoCloseable接口,这个接口的主要目的是自动进行关闭处理,但是这种处理一般不用,因为它必须结合try…catch

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class TestIO {
public static void main(String[] args) throws Exception{
File file = new File(File.separator + "Users" + File.separator + "白乐荣" +
File.separator + "Desktop"
+ File.separator + "hello.txt");
if (!file.getParentFile().exists()) { // 必须保证父目录存在
file.getParentFile().mkdirs() ; // 创建多级父目录
}
// OutputStream是一个抽象类,所以需要通过子类进行实例化,此时只能操作File类
try(OutputStream output = new FileOutputStream(file,true)){
// 要求输出到文件的内容
String msg = "我爱我自己\n" ;
// 将内容变为字节数组
output.write(msg.getBytes());
}catch (Exception e) {
e.printStackTrace();
}
}
}

必需要在try的括号里面调用对象。比较鸡肋,一般不建议使用这种方法。

3字节输入流:(InputStream)

我们已经实现了利用OutputStream将程序内容输出到文件的处理,下面使用InputStream类在程序中读取文件内容。

//InputStream类的定义如下:
public abstract class InputStream implements Closeable

发现InputStream类只实现了Closeable接口,在InputStream类中提供有入下方法:
1、读取数据到字节数组中,返回数据的读取个数。如果此时开辟的字节数组大小大于读取的数据大小,则返回的就是读取个数;如果要读取的数据大于数组内容,那么这个时候返回的就是数组长度;如果没有数据了还在读,则返回-1:public int read(byte b[])throws IOException.最常用的方法
2、读取部分数据到字节中,每次只读取传递数组的部分内容,如果读取满了则返回长度(len),如过没有读取满则返回读取的数据个数,如果读到最后没有数据了返回-1:public int ready(byte b[],int off,int len)throws IOException
3、读取单个字节,每次读取一个字节的内容明知道没有数据了返回-1:public abstract int read()throws IOException;
同OutputStream的使用一样,InputStream是一个抽象类,如果要对其实例化,同样也需要使用子类,如果文件进行处理,则使用FileInputStream类。

import java.io.*;

public class PartOutTest {
    public static void main(String[] args) throws IOException {
    //定义文件路径
        File file=new File("C:"+File.separator+"Users"+File.separator+"白乐荣"+
                               File.separator+"Desktop"+File.separator+"Tset.txt");
       //必须保证文件存在才能进行处理
        if(file.exists()){
            InputStream inputStream=new FileInputStream(file);
            byte[] data=new byte[1024];
            int len=inputStream.read(data);
            //将数据读取到字符数组中,这个字符数组相当于一个缓冲区
            String result=new String(data,0,len);
            System.out.println("读取内容【"+result+"】");
            inputStream.close();
        }
    }
}

我们从我们的整个操作流程可以发现OutputStream、InputStream类的使用形式上是非常类似的。

流程整理
  1:取得File对象
  2:取得file对象的输入、输出流
  3:进行数据的读取或写入操作
  4:关闭流(close()).

4、字符输出流:(Writer)

字符适合于处理中文数据,Writer是字符输出流的处理类,这个类的定义如下:

public abstract class writer implements Appendable,Closeable,Flushable

与我们的OutputStream相比多了一个Appendable接口
在Writer类里面也提供write()方法,而且该方法接收的类型都是char型,要注意的是,Writer类提供了一个直接输出字符串的方法:

//直接输出字符串
public void write(String str) throws IOException

如果要操作文件使用FileWriter子类

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class WriterTest {
    public static void main(String[] args) throws IOException {
    //取得文件对象
        File file=new File("C:"+File.separator+"Users"+File.separator+"白乐荣"+
                File.separator+"Desktop"+File.separator+"Hello.txt");
                //如果文件不存在,就创建
       if(!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
       }
       
        String msg="我爱我家";
        //获取输出流
        Writer writer=new FileWriter(file);
        //写入文件
        writer.write(msg);
        //关闭流
        writer.close();
    }
}

Writer类的结构与方法的使用与OutputStream非常相似,只是Writer类对于中文的支持很好并且提供了直接写入的String的方法而已。

5、字符输入流:Reader

Reader依然也是一个抽象类。如过要进行文件读取,同样的,使用FileReader。
Writer类中提供有方法直接向目标元写入字符串,而在Reader类中没有方法可以直接读取字符串类型,这个时候只能通过字符数组进行读取操作。

import java.io.*;

/*
* 这是一个将文件内容读取到输入流的程序
* */
public class ReadTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白乐荣"+
                File.separator+"Desktop"+File.separator+"Hello.txt");
     //取得文件按后保证文件存在
       if(file.exists()){
           //获取输入流
           Reader in=new FileReader(file);
           char [] data=new char[1024];
           int len=in.read(data);
           //进行数据读取
           String result=new String(data,0,len);
           System.out.println("读取内容【"+result+"】");
           in.close();
       }
    }
}

6、字节流VS字符流

使用字节流和字符流在代码的形式上差距不大,但是在实际的开发过程中,字节流一定是优先考虑的只有在处理中文的时候才会考虑字符流。因此所有的字符都需要通过内容缓冲来进行处理。所有的字符都需要通过内存缓冲来进行所有字符流的操作,无论写入还是输出,数据都先保存在缓存中。

//如果字符流不关闭,数据就有可能保存在缓存中没有输出到目标元。这种情况下就必须强制刷新才能够得到完整的数据。
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

/*
* 字符流的刷新操作*/
public class FlushTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白乐荣"+
                File.separator+"Desktop"+File.separator+"Hello.txt");
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        String msg="我爱你";
        Writer out=new FileWriter(file);
        out.write(msg);
        out.flush();//表示强制清空缓冲内容,所有内容输出
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值