java中的字节流的知识点---IO学习笔记(二)

IO流:

包括字节流和字符流。

在这里解释一下我对于流的理解,其实流就相当于一个用来运输字节或者字符的管道,一开始会把所有的数据存放到流中,然后我们再从流中取出数据(进行读取或者写出操作),每读或者写一次就会从管道中把读或者写的数据取出来,管道中就没有了你刚才读到或者写出的数据了。比如:

FileInputStream fis = new FileInputStream(String filename);

就会把文件名为filename的文件内容全部存放到管道中去,然后我们进行fis.read(),就会从管道中读取出内容,读到的内容就会从管道中消失。

字节流:

(1)InputStream:抽象了应用程序读取数据的方式

OutputStream : 抽象了应用程序写出数据的方式

(2)输入流的基本方法:

InputStream in = new InputStream();

int b = in.read();

读取一个字节无符号填充到int的最后8位,当读到-1时,标识读取到最后结束了。

in.read(byte[] buf):读取的数据填充到字节数组buf中

in.read(byte[] buf,int start ,int size):读取数据到字节数组buf,并且是从buf的start位置开始,存放size长度的数据

(3)输出流的基本方法:

OutputStream out = new OutputStream();

out.write(int b):写出一个字节到流,写的是int的最后的8位

out.write(byte[] buf):将buf字节数组都写入到流

out.write(byte[] buf,int start,int size):字节数组buf从start位置开始写size长度的字节到流

下面介绍字节流基本的读取方法的使用(注意:FileInputStream继承了InputStream)

package com.test.FileInputStream;

import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamTest {
    public static void main(String[] args) {
        try {
            System.out.println("方式一:字节数组的长度足够存储读取的内容");
            ReadFile1("C:\\Users\\Administrator\\Desktop\\javaIO\\读取的测试文件.txt");
            System.out.println();
            System.out.println("方式二:字节数组的长度不足以存储读取的内容");
            ReadFile2("C:\\Users\\Administrator\\Desktop\\javaIO\\读取的测试文件.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 当字节数组的大小足够存储读取的内容的时候
     * 只读取一次,然后打印出来就可以了
     */
    public static void ReadFile1(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];
        //从fis中批量读取字节,放入到buf这个字节数组中,
        //从第0个位置开始放,最多放buf.length个
        //返回的是读到的字节的个数
        int bytes = fis.read(buf, 0, buf.length);
        int j = 1;
        for(int i=0;i<bytes;i++){
        //byte类型8位,int类型32位,为了避免数据转换错误,通过&0xff将高24位清零
            System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
            if(j++%10==0){//每读取10个字节就换行
                System.out.println();
            }
        }
        fis.close();
    }

    /**
     * 当数组的大小没法存储读取的全部的字节的时候,
     * 就要对该字节数组进行重复利用,
     * 每读取字节数组的长度的内容的时候就打印出来,
     * 然后再次读取该字节数组长度的内容,
     * 直到把所有的内容读取出来
     */
    public static void ReadFile2(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];

        int bytes = 0;
        int j = 1;
        while((bytes = fis.read(buf, 0, buf.length))!=-1){//如果数组不是足够大,要进行多次的读取操作
            for(int i = 0;i<bytes;i++){
                System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
                    System.out.println();
                }
            }
        }
        fis.close();

    }
}

读取的文件内容:

读取结果截图:

下面对比下单字节读取与批量读取文件的效率:

package com.test.FileInputStream;

import java.io.FileInputStream;
import java.io.IOException;
/**
 * 对比单字节读取与批量读取同样的文件的所用的时间
 * 2015年8月8日 下午9:24:31
 *
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) {
        try {
            ReadFile1("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile2("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 单字节读取文件的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile1(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        int b;
        int i = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read())!=-1){
//          System.out.print(Integer.toHexString(b&0xff)+" ");
            if(i++%10==0){
//              System.out.println();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("单字节读取所用的时间:"+(end-start));
        fis.close();
    }

    /**
     * 批量字节读取的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile2(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];
        int b;
        int j = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read(buf, 0, buf.length))!=-1){
            for(int i = 0;i<b;i++){
//              System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("批量读取所用的时间:"+(end-start));
        fis.close();
    }
}

所以,批量读取,对于大文件而言效率高,也是我们最常见的读文件的方式。单字节读取不适合大文件,大文件读取的效率很低。

下面介绍字节流基本的写出方法的使用(注意:FileOutputStream继承了OutputStream,实现了向文件中写出byte数据的方法)

package com.test.FileOutputStream;

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest {

    public static void main(String[] args) {
        try {
            WriteFile("C:\\Users\\Administrator\\Desktop\\javaIO\\写入测试文件.txt");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void WriteFile(String filename) throws IOException{
        //如果该文件不存在,则直接创建,如果存在,删除后创建
        FileOutputStream fos = new FileOutputStream(filename);
//      //如果该文件不存在,则直接创建,如果存在,直接在文件中追加内容
//      FileOutputStream fos = new FileOutputStream(filename,true);
        /*
         * 写一个字符的方法(可以写一个字符)
         */
        fos.write(‘A‘);//写出了‘A’的字节所占位的最后八位
        fos.write(‘B‘);
        /*
         * 写一个整数的方法
         */
        int i = 10;//write()方法只能写八位,那么写一个int需要写4次,每次8位
        fos.write(i>>>24);
        fos.write(i>>>16);
        fos.write(i>>>8);
        fos.write(i);

        /*
         *写一个字节数组的方法 (可以直接写一个字节数组)
         */
        byte[] gbk = "小灰灰".getBytes("gbk");
        fos.write(gbk);

        fos.close();

    }

}

基本的字节输入流和字节输出流的整合运用:(以Copy文件为例)

package com.test.FileOutputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyFile {

    public static void main(String[] args) {
        File srcFile = new File("C:\\Users\\Administrator\\Desktop\\javaIO\\被copy的文件.txt");
        File destFile = new File("C:\\Users\\Administrator\\Desktop\\javaIO\\copy的文件.txt");
        try {
            copyFile(srcFile, destFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void copyFile(File srcFile,File destFile) throws IOException{
        if(!srcFile.exists()){
            throw new IllegalArgumentException("文件:"+srcFile+"不存在");
        }
        if(!srcFile.isFile()){
            throw new IllegalArgumentException(srcFile+"不是文件");
        }
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        byte[] buf = new byte[3*1024];
        int i;
        while((i = fis.read(buf,0,buf.length))!=-1){
            fos.write(buf, 0, i);
            fos.flush();
        }
        fis.close();
        fos.close();
    }

}

DataOutputStream/DataInputStream的使用:

作用:

对“流”功能的扩展,可以更加方便的读取int,long,字符等基本类型的数据。

构造方法:

DataOutputStream dos = new DataOutputStream(OutputStream out);

DataInputStream dis = new DataInputStream(InputStream in);

从构造方法中可以看到这两种流就是对普通流进行了包装,方便读取基本类型的数据。

DataOutputStream多出来的写出的方法:

writeInt()

writeDouble()

writeLong()

writeChars()//采用UTF-16BE编码写出

writeUTF()//采用UTF-8编码写出

……

writeInt():

write()方法一次只可以写出最后的8位,但是int类型的数据是32位(4个字节),所以要write()四次才能写出一个int类型的数据。

int i = 10;//write()方法只能写八位,那么写一个int需要写4次,每次8位
        fos.write(i>>>24);
        fos.write(i>>>16);
        fos.write(i>>>8);
        fos.write(i);

这是我们写一个int类型数据的方法。

writeInt()方法可以只写一次就可以写出一个int类型的数据,其实查看源码可以知道其实也是write()了四次。

writeInt()方法的源码:

 public final void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);
    }

writeLong(),writeDouble()……也是这样的原理。

所以可以看出DataOutputStream就是对基本类型的数据的写出方法进行了包装,方便我们写出基本类型的数据。

BufferedInputStream/BufferedOutputStream的使用:

这两个流为IO提供了带缓冲区的操作,一般打开文件进行写入或者读取操作时,都会加上缓冲,这种流模式提高了IO的性能。

解释:

从应用程序中把数据放入文件,相当于将一缸水倒入另一个缸中。

FileOutputStream—–>write()方法相当于一滴水一滴水的把水转过去

DataOutputStream—>writeXxx()方法会方便一些,相当于一瓢一瓢的转移过去

BufferedOutputStream—>write()方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入到另个缸中,性能提高了。

注意:当使用BufferedOutputStream的时候,当写完一次后要进行冲刷缓冲区(flush()),否则下次进行写入的时候就没法向缓冲区中存放了。

下面比较一下这些流读取和写入操作的效率:

package com.test.FileInputStream;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
/**
 * 对比单字节读取与批量读取同样的文件的所用的时间
 * 2015年8月8日 下午9:24:31
 *
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) {
        try {
            ReadFile1("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile2("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile3("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile4("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 单字节读取文件的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile1(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        int b;
        int i = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read())!=-1){
//          System.out.print(Integer.toHexString(b&0xff)+" ");
            if(i++%10==0){
//              System.out.println();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("单字节读取所用的时间:"+(end-start));
        fis.close();
    }

    /**
     * 批量字节读取的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile2(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];
        int b;
        int j = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read(buf, 0, buf.length))!=-1){
            for(int i = 0;i<b;i++){
//              System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("批量读取所用的时间:"+(end-start));
        fis.close();
    }

    /**
     * 字节缓冲流读取文件
     * @param filename
     * @throws IOException
     */
    public static void ReadFile3(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        BufferedInputStream bis = new BufferedInputStream(fis);
        long start = System.currentTimeMillis();
        int b;
        int j = 1;
        while((b=bis.read())!=-1){
            for(int i=0;i<b;i++){
//              System.out.println(Integer.toHexString(b&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("字节缓冲流读取所用的时间:"+(end-start));
        bis.close();
    }
    /**
     * 字节缓冲流批量读取文件
     * @param filename
     * @throws IOException
     */
    public static void ReadFile4(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] buf = new byte[1024*3];
        long start = System.currentTimeMillis();
        int b;
        int j = 1;
        while((b= bis.read(buf, 0, buf.length))!=-1){
            for(int i = 1;i<b;i++){
//              System.out.println(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("字节缓冲流批量读取所用的时间"+(end-start));
        bis.close();
    }
}

所用时间结果截图:

由此可以看出:

批量读取文件的效率>字符缓冲流读取文件的效率>单字节读取文件的效率

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-31 00:46:39

java中的字节流的知识点---IO学习笔记(二)的相关文章

java中字符流的知识点---IO学习笔记(三)

字符流: 文本和文本文件的区别: 文本: java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码). 文件: 文件是byte byte byte-的数据序列. 文本文件: 文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果. 字符流(Reader,Writer) 操作的是文本文件.对于mp3,二进制文件是字节文件不适合用字符流读取,因为读取出来的是char,没有意义. 字符的处理,一次处理一个字符 字符的

Java中Socket通信的知识回顾---学习笔记

两台计算机进行通信的基本前提: (1)IP地址: 每台计算机都有自己独一无二的IP地址,根据IP地址判断与哪台计算机进行通信. (2)端口号: 每个应用程序都有自己专属的端口,根据端口号判断与计算机中的哪个应用程序进行通信. 说明: <1>用于区分不同应用程序 <2>端口号的范围:0-65535,其中0-1023是为系统保留的端口号 <3>常用的协议的端口号: http:80 ftp:21 telnet:23 <4>IP地址+端口号=Socket,Socke

java中的对象的序列化与反序列化的知识点---IO学习笔记(四)

对象的序列化,反序列化 对象的序列化: 就是将Object转换成byte序列 对象的反序列化: 将byte序列转换成Object 序列化流,反序列化流 序列化流(ObjectOutputStream),是字节的过滤流->主要方法:writeObject() 反序列化流(ObjectInputStream)->主要方法:readObject() 序列化接口(Serializable) 对象必须实现序列化接口,才能进行序列化,否则将出现异常 这个接口,没有任何方法,只是一个标准. 基本的对象序列化

1.JAVA中使用JNI调用C++代码学习笔记

Java 之JNI编程1.什么是JNI? JNI:(Java Natibe Inetrface)缩写. 2.为什么要学习JNI?  Java 是跨平台的语言,但是在有些时候仍然是有需要调用本地代码 (这些代码通常是由C/C++编写的). Sun公司提供的JNI是Java平台的一个功能强大的接口.这个JNI接口提供了Java与操作系统本地代码互相调用的功能.(即java调用C++代码) 最简单的Java调用C/C++代码步骤 1.创建TestNativeCode工程,新建cn.itcast包,新建

java中常见的输入输出流案例学习

字节输入流: 1.FileInputStream 用途:从文件系统中的文件获得输入字节,常用于读取图像.声音等原始字节流,读取字符流可考虑使用FileReader 详细构造函数与常用方法可参考API文档,网上已经有中文版的API了,我是个E文盲,伤不起 这里介绍一个最常见的方法: read(byte[] b, int off, int len) 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中. ->off:b字节数组中的偏移量 小知识:数组偏移量,比如a[1,2,3,4,5]

Java IO学习笔记:概念与原理

Java IO学习笔记:概念与原理 一.概念 Java中对文件的操作是以流的方式进行的.流是Java内存中的一组有序数据序列.Java将数据从源(文件.内存.键盘.网络)读入到内存 中,形成了流,然后将这些流还可以写到另外的目的地(文件.内存.控制台.网络),之所以称为流,是因为这个数据序列在不同时刻所操作的是源的不同部分. 二.分类 流的分类,Java的流分类比较丰富,刚接触的人看了后会感觉很晕.流分类的方式很多: 1.按照输入的方向分,输入流和输出流,输入输出的参照对象是Java程序. 2.

【DAY12】第十二天集合&泛型&IO学习笔记

hash:散列 ------------------ Hashset集合内部是通过HashMap进行实现的.使用的是HashMap中key部分. 对象在添加进集合中时,首选会对hashcode进行处理(hashcode右移16位和 自身做异或运算)得到一个经过处理的hash值,然后该值和集合的容量进行 &运算,得到介于0和集合容量值之间一个数字.该数字表示着数组的下标. 也就是该元素应该存放在哪个元素中. Map与Collection -------------- Map与Collection在

JavaSE中线程与并行API框架学习笔记——线程为什么会不安全?

前言:休整一个多月之后,终于开始投简历了.这段时间休息了一阵子,又病了几天,真正用来复习准备的时间其实并不多.说实话,心里不是非常有底气. 这可能是学生时代遗留的思维惯性--总想着做好万全准备才去做事.当然,在学校里考试之前当然要把所有内容学一遍和复习一遍.但是,到了社会里做事,很多时候都是边做边学.应聘如此,工作如此,很多的挑战都是如此.没办法,硬着头皮上吧. 3.5 线程的分组管理 在实际的开发过程当中,可能会有多个线程同时存在,这对批量处理有了需求.这就有点像用迅雷下载电视剧,假设你在同时

Laravel陌生知识点快速学习(二)

Laravel陌生知识点快速学习(二) Authentication用户授权登陆 midlleware中间件,即需要通过它的验证,才能够访问以下界面 例如博客,管理界面需要用户登陆才能访问,游客是不能进入的 以下是路由器的写法 Route::group(['prefix' => 'console', 'middleware' => 'auth'], function(){ Route::any('/', 'console\[email protected]'); Route::resource