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

目录
  • 字节输出流OutputStream
    • 字符输出流
    • 字节输入流InputStream
    • 字符输入流Reader
    • 字节流和字符流的区别
  • 总结

我先解释一下什么叫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以上)

我把思路也贴给大家:

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

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

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java 输入流中的read(byte[] b)方法详解

    我就废话不多说了,大家还是直接看代码吧~ public int read(byte[] b) throws IOException 从一个输入流中读取一定数量的字节,并将这些字节存储到其缓冲作用的数组b中.这个函数会返回一次性读取的字节数. 这个函数是一个阻塞式的函数,当它读到有效数据.确认的文件尾(EOF)或者抛出一个异常时它才会执行其他语句,否则一直停在read()函数处等待. 比如下面的列子: ServerSocket server = new ServerSocket(port) Soc

  • Java字节流和字符流总结IO流!

    目录 从接收输入值说起 字节流读取 字符流读取 Scanner 读取 什么是 IO 流 字节流和字符流 字节流 字节输入流 字节输出流 缓冲流的原理 字符流 字符输入流 字符输出流 RandomAccessFile 总结 从接收输入值说起 在日常的开发应用中,有时候需要直接接收外部设备如键盘等的输入值,而对于这种数据的接收方式,我们一般有三种方法:字节流读取,字符流读取,Scanner 工具类读取. 字节流读取 直接看一个例子: public class Demo01SystemIn { pub

  • JAVA输出流与输入流代码实例

    这篇文章主要介绍了JAVA输出流与输入流代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 输出流 编程入门的第一个程序,输出一串字符串 public class C { public static void main(String[] args) { System.out.println("Holle JAVA"); //输出 } } 输入流 输入流需要引用包的概念,包里面存放的是类.输入流需要实例化InputStreamRea

  • Java使用字节流实现图片音频的复制

    Java字节流复制图片音频 java中的字节流可以实现文本的读入写入,当然也可以实现字节流对于图片的读入写入,就只需要写一个复制文本的字节输入输出流,然后在源文件和目标文件更换后缀图片就行了. 下面给出了source.png图片的路径,我们对其所对应的路径提供一个copysource.png的复制图片文件. 1.首先找到这两个文件的路径.如果写入的文本没有创建的话,会自动创建. File source = new File("C:\\Users\\Lenovo\\Desktop\\csdn\\i

  • java中的char占几个字节实例分析

    java中的char占几个字节实例分析 1:"字节"是byte,"位"是bit : 2: 1 byte = 8 bit : char 在Java中是2个字节.java采用unicode,2个字节(16位)来表示一个字符. 例子代码如下: public class Test { public static void main(String[] args) { String str= "中"; char x ='中'; byte[] bytes=nu

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

    目录 字节输出流OutputStream 字符输出流 字节输入流InputStream 字符输入流Reader 字节流和字符流的区别 总结 我先解释一下什么叫IO流: I:指的是InputStream,这是一个抽象类,最常用的子类是FileInputStream O:值得是OutputStream,这也是一个抽象类,最常用的子类是OutputStream 流:由于在进行文件操作的时候大多数是用的byte数据,这些数据并不是一次性写入(读取),而是像水龙头那样慢慢的流(想象一下你接水的场景) 废话

  • Java中char[] 和 String 类型占用字节大小问题

    作者:威威喵 原文链接:https://blog.csdn.net/smile_Running/article/details/87211916 在 C 语言中 1.char a[10] = {"China"} 中,这个 a 占用多少字节? 答:占用 10 个字节. 解析:上面代码对 a 做了赋值的操作, a[0]='C' ,a[1]='h' ,a[2]='i' ,a[3]='n' ,a[4]='a' ,a[5]='\0',a[6]='\0',a[7]='\0',a[8]='\0',a

  • 举例讲解Java中Piped管道输入输出流的线程通信控制

    PipedOutputStream和PipedInputStream 在java中,PipedOutputStream和PipedInputStream分别是管道输出流和管道输入流. 它们的作用是让多线程可以通过管道进行线程间的通讯.在使用管道通信时,必须将PipedOutputStream和PipedInputStream配套使用. 使用管道通信时,大致的流程是:我们在线程A中向PipedOutputStream中写入数据,这些数据会自动的发送到与PipedOutputStream对应的Pip

  • java中利用List的subList方法实现对List分页(简单易学)

    以下是介绍利用List的subList方法实现对List分页,废话不多说了,直接看代码把 /** *//** * List分页 * 实现:利用List的获取子List方法,实现对List的分页 * @author 显武 * @date 2010-1-8 16:27:31 * */ import java.util.ArrayList; import java.util.List; public class PageModel { private int page = 1; // 当前页 publ

  • Java中字符数组、String类、StringBuffer三者之间相互转换

    一.StringBuffer与String的相互转换 1.将StringBuffer转换成String StringBuffer类成员toString函数可将其转换成String类型. StringBuffer buffer = newStringBuffer("abcd"); String str = buffer.toString(); 通过String类中的构造将一个StringBuffer类转换为String类:String(StringBuffer buffer) Strin

  • JAVA中的基本数据类型

    byte: java中最小的数据类型.1字节/8位.-128(2^7)~127(2^7-1),默认值0. short: 短整型,2字节/16位,取值范围-32768(--2^15)~32767(2^15-1),默认值0 int: 整型,4字节/32位,取值范围-2147483648(-2^31)~2147483647(2^31-1),默认值0 long: 长整型,8字节/64位,-2^63(-2^63)~2^63-1(2^63-1),默认值0L float: 浮点型,4字节/32位,用于存储带小

  • java中关于文本文件的读写方法实例总结

    本文实例总结了java中关于文本文件的读写方法.分享给大家供大家参考,具体如下: 写文本数据 方法 一: import java.io.*; public class A { public static void main(String args[]) { FileOutputStream out; PrintStream ps; try { out = new FileOutputStream("a.txt"); ps = new PrintStream(out); ps.print

  • 学习Java中的日期和时间处理及Java日历小程序的编写

    Java 在 java.util 包中提供了 Date 类,这个类封装了当前的日期和时间. Date 类支持两种构造函数.第一个构造函数初始化对象的当前日期和时间. Date( ) 下面的构造函数接收一个参数等于自1970年1月1日午夜起已经过的毫秒数 Date(long millisec) 一旦有一个可用的日期对象,可以调用以下任何一种支持的方法使用时间: SN 方法和描述 1 boolean after(Date date) 如果调用Date对象包含或晚于指定的日期则返回true,否则,返回

  • Java中集合关系图及常见操作详解

    下面是一张下载的Java中的集合类型的继承关系图,便于正确的理解和使用相应的集合类型. 几个面试常见问题: 1.Q:ArrayList和Vector有什么区别?HashMap和HashTable有什么区别? A:Vector和HashTable是线程同步的(synchronized).性能上,ArrayList和HashMap分别比Vector和Hashtable要好. 2.Q:大致讲解java集合的体系结构 A:List.Set.Map是这个集合体系中最主要的三个接口.       其中Lis

随机推荐