Java中的字节,字符输出流与字节和字符输入流的简单理解

作者:鱼小洲 时间:2022-11-30 01:56:13 

我先解释一下什么叫IO流:

  • I:指的是InputStream,这是一个抽象类,最常用的子类是FileInputStream

  • O:值得是OutputStream,这也是一个抽象类,最常用的子类是OutputStream

  • 流:由于在进行文件操作的时候大多数是用的byte数据,这些数据并不是一次性写入(读取),而是像水龙头那样慢慢的流(想象一下你接水的场景)

废话还是不多bb,先来一份简单的代码:


File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       if (!file.exists()){
           file.createNewFile();
       }

其中File.separator指的是当前系统的默认分隔符,这样写的原因是可以保证Java文件在Windows系统运行时和Linux系统运行时都不会出错

这段代码也很简单,主要就是创建一个文件。

当然,这都不是重点,重点在下面

字节输出流OutputStream

对于Output Stream类来说,它本身定义的是一个抽象类,按照抽象类的原则来讲,需要定义抽象类的子类,而我们要执行的是文件操作,则可以使用FileOutputStream子类来完成。而我们最关心的还是子类中的构造方法

方法描述
public FileOutputStream(File file) throws FileNotFoundException实例化FileOutputStream,主要用于新建数据
public FileOutputStream(File file,boolean append) throws FileNotFoundException实例化FileOutputStream,主要用于追加数据

我们在实例化OutputStream对象之后肯定要进行输出操作。在OutputStream类中定义了3个输出方法。例如:

方法描述
public abstract void write(int b) throws IOException输出单个字节数据
public void write(byte[] b) throws IOException输出一组字节数据
public abstract void write(byte[] b,int off,int len) throws IOException输出部分字节数据

可能大家在看表的时候已经发现了,都是byte类型的数据。

使用OutputStream向文件中输出数据。


import java.io.*;
public class test {
   public static void main(String[] args) throws Exception{
       File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       if (!file.exists()){
           file.createNewFile();
       }
       OutputStream output=new FileOutputStream(file);// 实例化父类
       String data="Hello World!";
       output.write(data.getBytes());
       output.close();
       }
}

可以发现,在文件输出的过程中,如果要输出的文件和目录不存在那么会覆盖掉原有的内容,咋办呢?别忘了我们还有一个构造方法专门是为了追加数据的:


import java.io.*;
public class test {
   public static void main(String[] args) throws Exception{
       File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       if (!file.exists()){
           file.createNewFile();
       }
       OutputStream output=new FileOutputStream(file,true);// 追加数据
       String data="Hello World!";
       output.write(data.getBytes());
       output.close();
       }
}

执行一遍会发现,会自动的把数据附加在已有的数据后面。

我们在来看看另一种类似的流

字符输出流

看标题,字节和字符就差一个字,但是,熟悉Java数据基本类型的都知道。这俩货一个是byte,一个是String。那么我们在对文件进行输出操作的时候,就可以把需要输出的内容定义成String类型而不是byte字节型;

同样,Writer也是一个抽象类,当我们用于文件操作的时候,常用的子类就是FileWriter。我们来看看Writer类的常用方法:

方法描述
public abstract void close() throws IOException关闭输出流
public void write(String str) throws IOException将字符串输出
public void write(char[] cbuf) throws IOException将字符数组输出
public abstract void flush() throws IOException强制性清空内存

还是不多bb,上代码,就知道啥样子了:


import java.io.*;
public class test {
   public static void main(String[] args) throws Exception{
       File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       if (!file.exists()){
           file.createNewFile();
       }
       Writer out=new FileWriter(file);
       String data="Hello World!";
       out.write(data);
       out.close();
       }
}

了解了输出流,我们再来看看输入流;

Java中的输入流有两种,一种是InputStream,另一种就是Reader。看这名字就知道,md,可能又是一种简单的一种难的。没错,你猜对了;

字节输入流InputStream

同样,这货也是一个抽象类,用于文件操作的也是他的子类FileInputStream,当然也有几个方法用于操作文件:

方法描述
public abstract int read() throws IOException读取单个字节数据,每次执行read()方法都会读取一个数据源的指定数据,如果已经读到了结尾,则会返回-1
public int read(byte[] b) throws IOException读取多个字节数据,如果要读取的数据小于byte的数据,这个时候read()方法的返回值int返回的是数据个数,如果现在开辟的字节数组小于读取的长度,且数据已经读取完了。则这个时候返回的是-1
public int read(byte[] int off,int len) throws IOException读取指定多个字节数据

我们还是看看读取内容,具体代码怎么去实现它:


import java.io.*;
public class test {
   public static void main(String[] args) throws Exception{
       File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       if(file.exists()){
InputStream input=new FileInputStream(file);
byte data[] = new byte[1024];// 开辟一个1024长度的byte数组
int len=input,read(data);
input.close();
System.out.println("读取的内容:"+new String(data,0,lem));
}
       }
}

上述代码简明的表达了读取文件的全部内容的逻辑,但是想象一下,单个单个的读取怎么做呢?

这时候需要一点以前的知识了,看看代码:


import java.io.*;
public class test {
   public static void main(String[] args) throws Exception{
       File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       if(file.exists()){
       InputStream input=new FileInputStream(file);
       byte data[] = new data[1024];
       int foot=0;// 数组的索引初始值
       int temp=0;// 待会自己看是啥作用
       while((temp=input.read())!=-1){
       data[foot++]=(byte) temp;
       input.close();
       System.out.println("读取到的数据是:"+new String(data,0,foot));
}
}
       }
}

了解了字节输入流,是不是还得了解一下字符输入流。来吧,也别愣着了,码代码呗;

字符输入流Reader

那些啥抽象啊,子类啊啥的我都不说了,反正类似,自己慢慢琢磨琢磨。

看看有哪些方法:

方法描述
public abstract void close() throws IOException关闭流
public int read() throws IOException读取单个字符
public int read(char[] cbuf) throws IOException将内容读到字符数组中,返回读入的长度

有一点和上面的不一样:

虽然Writer类中提供了输出字符串数据的操作方法,但是在Reader类中并没有这样的定义。之所以会这个样子,完全是因为在使用OutputStream输出数据时,其程序可以输出的大小一定是程序可以承受的数据大小,如果在使用InputStream读取时,可能被读取的数据灰常大,一次性全部读取的话可能会问题,于是就只有一个一个的读取


import java.io.*;
public class test {
   public static void main(String[] args) throws Exception{
       File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       Reader in=new FileReader(file);
       char data[] = new char[1024];
       int len=in.read(data);
       in.close();
       System.out.println("读取的内容:"+new String(data,0,len));
       }
}

代码写了这么一大堆,我们最后再看看一个问题;

字节流和字符流的区别

通过以上的代码演示我们知道了,字节流和字符流都有类似的功能,那么在开发的过程中具体使用哪一种呢?

他们的区别在于:

字节流在进行IO操作时,直接针对的时操作的数据终端(如文件),而字符流操作时不是直接针对于终端,而是针对于缓存区(理解为内存)的操作,而后由缓存区来操作终端(如文件),这属于间接操作,按照这样的方式,如果在使用字节流时不关闭最后的输出操作,也可以将所有的内容进行输出,而使用字符流时如果不关闭,则意味着缓冲区的内容不会被输出,当然,这个时候可以由用户自己调用flush()方法去强制性的手动清空 例如:


import java.io.*;
public class test {
   public static void main(String[] args) throws Exception{
       File file=new File("e:"+File.separator+"JavaLearn"+File.separator+"EleventhDemo"+File.separator+"1.txt");
       if (!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
           System.out.println("父级目录创建成功");
       }
       if (!file.exists()){
           file.createNewFile();
       }
       Writer out=new FileWriter(file);
       String data="Hello World!";
       out.write(data);
       out.flush();
       }
}

总结一下,字节流和字符流的主要区别:

  • 字节流没有使用到缓冲区,而字符流使用了;

  • 处理各种数据都可以通过字节流完成,而在处理中午的时候使用字符流会更方便;

最后,留一个思考题给有兴趣的小伙伴。

现有一个要求,按照DOS系统的文件拷贝命令,由初始化参数输入源文件和拷贝文件的路径,而后执行操作。

提示:本程序直接在主方法中完成,不考虑多余的方法和类的设计。考虑大文件的情况(500MB以上)

我把思路也贴给大家:

方案一:将要复制的文件全部读取到内存中,而后将所有的内容一次性输出到目标文件;

方案二:采用边读边写的方式一点一点的进行文件的复制。

来源:https://blog.csdn.net/weixin_43581288/article/details/104747704

标签:Java,字符,输入流字节,字符输出流
0
投稿

猜你喜欢

  • Spring Boot + thymeleaf 实现文件上传下载功能

    2022-05-22 03:56:13
  • C#清除WebBrowser中Cookie缓存的方法

    2022-01-13 20:01:08
  • Java学习基础之安装JDK/配置JDK环境&IEDA工具安装

    2023-02-09 13:02:40
  • 你真的了解Java的多线程方法吗

    2022-02-01 22:55:40
  • Netty与NIO超详细讲解

    2022-08-16 00:44:37
  • JDK线程池和Spring线程池的使用实例解析

    2023-02-24 13:27:32
  • C#利用iTextSharp添加PDF水印

    2022-03-23 23:37:44
  • eclipse的web项目实现Javaweb购物车的方法

    2023-07-28 15:55:53
  • java判断字符串String是否为空问题浅析

    2023-08-25 07:06:06
  • Android Path绘制贝塞尔曲线实现QQ拖拽泡泡

    2023-03-16 07:57:24
  • C#实体对象序列化成Json并让字段的首字母小写的两种解决方法

    2023-02-24 18:41:44
  • Android Activity切换(跳转)时出现黑屏的解决方法 分享

    2022-10-25 15:41:07
  • Java实现小型图书馆管理系统

    2021-06-14 04:27:35
  • 详解Android WebView加载html片段

    2023-04-23 11:40:12
  • 简单学习C#中的泛型方法使用

    2022-11-06 19:37:27
  • C语言实现BMP图像处理(哈夫曼编码)

    2022-10-08 02:04:02
  • spring与disruptor集成的简单示例

    2021-12-16 11:01:41
  • Android中View跟随手指移动效果

    2021-07-26 00:21:18
  • IntelliJ IDEA2022.3 springboot 热部署含静态文件(最新推荐)

    2023-07-07 10:41:58
  • Android中的SpannableString与SpannableStringBuilder详解

    2022-03-02 22:04:55
  • asp之家 软件编程 m.aspxhome.com