ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

IO流

2022-08-12 13:31:24  阅读:167  来源: 互联网

标签:读取 int System IOException IO out 字节


1、JAVA流式输入输出原理

在Java程序中,对于数据的输入/输出操作以“流”(Stream)方式进行;J2SDK提供了各种各样的“流”类,用以获取不同种类的数据:程序中通过标准的方法输入或输出数据。

流是用来读写数据的,java有一个类叫File,它封装的是文件的文件名,只是内存里面的一个对象,真正的文件是在硬盘上的一块空间,在这个文件里面存放着各种各样的数据


2、输入输出流分类

Java.io 包中定义了多个流类型(类或抽象类)来实现输入/输出功能;可以从不同的角度对其进行分类:

  • 按数据流的方向不同可以分为输入流和输出流

  • 按照处理数据单位不同可以分为字节流和字符流

  • 按照功能不同可以分为节点流和处理流

J2SDK所提供的所有流类型位于包 Java.io内,都分别继承自以下四种抽象流类型。

  • 输入流:InputStream(字节流)

    • Reader(字符流)
  • 输出流:OutputStream(字节流)

    • Writer(字符流)

3、节点流和处理流

3.1、节点流类型

类型 字符流
File(文件) FileReader、FileWriter
Memory Array CharArrayReader、CharArrayWriter
Memory String StringReader、StringWriter
Pipe(管道) PipedReader、PipedWriter

节点流就是一根管道直接插到数据源上面,直接读数据源里面的数据,或者是直接往数据源里面写入数据。典型的节点流是文件流:文件的字节输入流(FileInputStream),文件的字节输出流(FileOutputStream),文件的字符输入流(FileReader),文件的字符输出流(FileWriter)。

3.2、处理流类型

处理流是包在别的流上面的流,相当于是包到别的管道上面的管道

处理类型 字符流 字节流
Buffering BufferedReader、BufferedWriter BufferedInputStream、BufferedOutputStream
Filtering FilterReader、FilterWriter FilterInpuStream、FilterOutputStream
Converting between byte and character InputStreamReader、OutputStreamWriter -
Object serialization - ObjectInputStream、ObjectOutputStream
Data conversion - DataInputStream、DataOutputStream
Counting LineNumberReader LineNumberInputStream
Peeking ahead PusbackReader PusbackInputStream
Printing PrintWriter PrintStream

4、InputStream(输入流)

我们看到的具体的某一些管道,凡是以InputStream结尾的管道,都是以字节的形式向我们的程序输入数据。

继承自InputStream的流都是用于向程序中输入数据,且数据的单位为字节(8bit);下图中深色为节点流,浅色为处理流。

4.1、InputStream的基本方法

//读取一个字节并以整数的形式返回(0~255)
//如果返回-1就说明已经到了输入流的末尾 
int read() throws IOException 
    
//读取一系列字节并存储到一个数组buffer 
//返回实际读取的字节数,如果读取前已到输入流的末尾,则返回-1 
int read(byte[] buffer) throws IOException 

//读取length个字节 
//并存储到一个字节数组buffer,从length位置开始 
//返回实际读取的字节数,如果读取前以到输入流的末尾返回-1. 
int read(byte[] buffer,int offset,int length) throws IOException 
    
//关闭流释放内存资源
void close() throws IOException 
    
//跳过n个字节不读,返回实际跳过的字节数
long skip(long n) throws IOException

read()方法是一个字节一个字节地往外读,每读取一个字节,就处理一个字节。

read(byte[] buffffer)方法读取数据时,先把读取到的数据填满这个byte[]类型的数组buffffer(buffffer是内存里面的一块缓冲区),然后再处理数组里面的数据。

4.2、案例

import java.io.*; 
public class TestFileInputStream { 
    public static void main(String args[]) { 
        int b = 0;// 使用变量b来装调用read()方法时返回的整数 
        FileInputStream in = null; 
        // 使用FileInputStream流来读取有中文的内容时,读出来的是乱码,因为使用 InputStream流里面的read()方法读取内容时是一个字节一个字节地读取的,而一个汉字是占用两个 字节的,所以读取出来的汉字无法正确显示。
        // FileReader in = null; 
        // 使用FileReader流来读取内容时,中英文都可以正确显示,因为Reader流里面的 read()方法是一个字符一个字符地读取的,这样每次读取出来的都是一个完整的汉字,这样就可以正确 显示了。
        try {
            in = new FileInputStream("");
            // in = new FileReader("");
        } catch (FileNotFoundException e) { 
            System.out.println("系统找不到指定文件!"); 
            System.exit(-1);// 系统非正常退出
        }
        long num = 0;// 使用变量num来记录读取到的字符数
        
        // 调用read()方法时会抛异常,所以需要捕获异常
        try {
            while ((b = in.read()) != -1) { 
                // 调用int read() throws Exception方法时,返回的是一个int类型的整 数 
                // 循环结束的条件就是返回一个值-1,表示此时已经读取到文件的末尾了。 
                // System.out.print(b+"\t");
                //如果没有使用“(char)b”进行转换,那 么直接打印出来的b就是数字,而不是英文和中文了 
                System.out.print((char) b);
                // “char(b)”把使用数字表示的汉字和英文字母转换成字符输入
                num++;
            }
            in.close();// 关闭输入流 
            System.out.println(); 
            System.out.println("总共读取了" + num + "个字节的文件");
        } catch (IOException e1) { 
            System.out.println("文件读取错误!"); 
        } 
    } 
}

5、OutputStream(输出流)

继承自OutputStream的流是用于程序中输出数据,且数据的单位为字节(8bit):下图中深色的为节点流,浅色为处理流。

5.1、OutputStream的基本方法

//向输出流中写入一个字节数据,该字节数据为参数b的低8位 
void write(int b) throws IOException 
    
//将一个字节类型的数组中的数据写入输出流 
void write(byte[] b) throws IOException 
    
//将一个字节类型的数组中的从指定位置(off)开始的len个字节写入到输出流 
void write(byte[] b,int off,int len) throws IOException 
    
//关闭流释放内存资源 
void close() throws IOException 
    
//将输出流中缓冲的数据全部写出到目的地 
void flush() throws IOException

5.2、案例

import java.io.*;
public class TestFileOutputStream { 
    public static void main(String args[]) {
        int b = 0;
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream("");
            out = new FileOutputStream("");
            // 指明要写入数据的文件,如果指定的路径中不存在这样的文 件,则系统会自动创建一个
            while ((b = in.read()) != -1) { 
                out.write(b); 
                // 调用write(int c)方法把读取到的字符全部写入到指定文件中去 
            }
            in.close();
            out.close(); 
        } catch (FileNotFoundException e) { 
            
            System.out.println("文件读取失败"); System.exit(-1);// 非正常退出
        } catch (IOException e1) {
            System.out.println("文件复制失败!"); 
            System.exit(-1); 
        }
        System.out .println("Student.StudentNew.java里面");
    }
}

6、Reader流

Reader : 和InputStream一模一样,唯一的区别就在于读的数据单位不同继承自Reader的流都是用于向程序中输入数据,且数据的单位为字符(16bit)

6.1、Reader的基本方法

//读取一个字节并以整数的形式返回(0~255)
//如果返回-1就说明已经到了输入流的末尾 
int read() throws IOException 
    
//读取一系列字节并存储到一个数组buffer 
//返回实际读取的字节数,如果读取前已到输入流的末尾,则返回-1 
int read(byte[] buffer) throws IOException 
    
//读取length个字节 
//并存储到一个字节数组buffer,从length位置开始 
//返回实际读取的字节数,如果读取前以到输入流的末尾返回-1.
int read(byte[] buffer,int offset,int length) throws IOException 
    
//关闭流释放内存资源
void close() throws IOException 
    
//跳过n个字节不读,返回实际跳过的字节数 
long skip(long n) throws IOException

7、Writer流

继承自Writer的流都是用于程序中输出数据,且数据的单位为字符(16bit)

7.1、Writer的基本方法

//向输出流中写入一个字节数据,该字节数据为参数b的低16位
void write(int b) throws IOException
    
//将一个字节类型的数组中的数据写入输出流 
void write(byte[] b) throws IOException 
    
//将一个字节类型的数组中的从指定位置(off)开始的len个字节写入到输出流 
void write(byte[] b,int off,int len) throws IOException 
    
//关闭流释放内存资源 
void close() throws IOException 
    
//将输出流中缓冲的数据全部写出到目的地
void flush() throws IOException

8、处理流

8.1、Buffering(缓冲流)

缓冲流要”套接“在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。J2SDK提供了四种缓冲流,常用构造方法如下:

BufferedReader(Reader in) 
BufferedReader(Reader in,int sz) //sz 为自定义缓冲区的大小 
BufferedWriter(Writer out) 
BufferedWriter(Writerout,int sz)
BufferedInputStream(InputStream in) 
BufferedInputStream(InputStream in,int size) 
BufferedOutputStream(InputStream in) 
BufferedOutputStream(InputStream in,int size)
  • 缓冲输入流支持其父类的mark和reset方法。

  • BufffferedReader提供了readLine方法用于读取一行字符串

  • BufffferedWriter提供了newLine用于写入一个行分隔符

  • 对于输出的缓冲流,写出的数据会现在内存中缓存,使用flflush方法将会使内存中的数据立刻写出

缓冲区(Buffffer)就是内存里面的一小块区域,读写数据时都是先把数据放到这块缓冲区域里面,减少io对硬盘的访问次数,保护我们的硬盘。

import java.io.*; 
public class TestBufferStream { 
    public static void main(String args[]) { 
        FileInputStream fis = null; 
        try {
            fis = new FileInputStream(""); 
            // 在FileInputStream节点流的外面套接一层处理流BufferedInputStream 
            BufferedInputStream bis = new BufferedInputStream(fis);
            int c = 0;
            System.out.println((char) bis.read()); 
            bis.mark(100);// 在第100个字符处做一个标记 
            for (int i = 0; i <= 10 && (c = bis.read()) != -1; i++) { 
                System.out.print((char) c); 
            }
            System.out.println();
            bis.reset();// 重新回到原来标记的地方 
            for (int i = 0; i <= 10 && (c = bis.read()) != -1; i++) { 
                System.out.print((char) c); 
            }
            bis.close();
        } catch (FileNotFoundException e) { 
            e.printStackTrace();
        } catch (Exception e1) { 
            e1.printStackTrace(); 
        } 
    }
}

8.2、转换流

  • InputStreamReader 和 OutputStreamWriter 用于字节数据到字符数据之间的转换

  • InputStreamReader 需要和 InputStream “套接” 。

  • OutputStreamWriter 需要和 OutputStream “套接” 。

  • 转换流在构造时可以指定其编码集合

InputStream isr = new InputStreamReader(System.in,"ISO8859-1")

转换流非常的有用,它可以把一个字节流转换成一个字符流,转换流有两种,一种叫InputStreamReader,另一种叫OutputStreamWriter。

InputStream是字节流,Reader是字符流,InputStreamReader就是把InputStream转换成Reader。

OutputStream是字节流,Writer是字符流,OutputStreamWriter就是把OutputStream转换成Writer。

把OutputStream转换成Writer之后就可以一个字符一个字符地通过管道写入数据了,而且还可以写入字符串。

import java.io.*;
public class TestTransform1 { 
    public static void main(String args[]) { 
        try {
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(""));
            osw.write("MircosoftsunIBMOracleApplet");
            // 把字符串写入到指定的文件 中去 
            System.out.println(osw.getEncoding());
            // 使用getEncoding()方法取得 当前系统的默认字符编码 
            osw.close();
            osw = new OutputStreamWriter(new FileOutputStream( "", true), "ISO8859_1");
            // 如果在调用FileOutputStream的构造方法时没有加入true,那么新加入的字符 串就会替换掉原来写入的字符串,在调用构造方法时指定了字符的编码 
            osw.write("MircosoftsunIBMOracleApplet");
            // 再次向指定的文件写入字符 串,新写入的字符串加入到原来字符串的后面 
            System.out.println(osw.getEncoding());
            osw.close(); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 
}

8.3、数据流

  • DataInputStream 和 DataOutputStream 分别继承自InputStream 和 OutputStream , 它属于处理流,需要分别“套接”在InputStream 和 OutputStream类型的节点流上。

  • DataInputStream 和 DataOutputStream 提供了可以存取与机器无关的Java原始类型数据(int,double等)的方法。

  • DataInputStream 和 DataOutputStream 的构造方法

DataInputStream (InputStream in)
DataOutputStream (OutputStream out)
import java.io.*; 
public class TestDataStream{
    public static void main(String args[]){ 
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //在调用构造方法时,首先会在内存里面创建一个ByteArray字节数组
        DataOutputStream dos = new DataOutputStream(baos); 
        //在输出流的外面套上一层数据流,用来处理int,double类型的数 
        try{
            dos.writeDouble(Math.random());//把产生的随机数直接写入到字节数组 ByteArray中 
            dos.writeBoolean(true);//布尔类型的数据在内存中就只占一个字节
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            System.out.println(bais.available()); 
            DataInputStream dis = new DataInputStream(bais); 
            System.out.println(dis.readDouble());
            //先写进去的就先读出来,调用 readDouble()方法读取出写入的随机数 
            System.out.println(dis.readBoolean());
            //后写进去的就后读出来,这里面 的读取顺序不能更改位置,否则会打印出不正确的结果 
            dos.close(); 
            bais.close(); 
        }catch(Exception e){
            e.printStackTrace(); 
        }
    } 
}

8.4、Print(打印流)

  • PrintWriter 和 PrintStream 都属于输出流,分别针对与字符和字节

  • PrintWriter 和 PrintStream 提供了重载的print

  • Println方法用于多种数据类型的输出

  • PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息

  • PrintWriter 和 PrintStream有自动flflush功能

PrintWriter(Writer out)
PrintWriter(Writer out,boolean autoFlush) 
PrintWriter(OutputStream out) 
PrintWriter(OutputStream out,boolean autoFlush)
PrintStream(OutputStream out) 
PrintStream(OutputStream out,boolean autoFlush)
import java.io.*; 
public class TestPrintStream{
    public static void main(String args[]){
        PrintStream ps = null;
        try{FileOutputStream fos = new FileOutputStream("E:\\log.txt");
            ps = new PrintStream(fos);//在输出流的外面套接一层打印流,用来控制打印 输出 
            if(ps != null){
                System.setOut(ps);
                //这里调用setOut()方法改变了输出窗口,以前写 System.out.print()默认的输出窗口就是命令行窗口.
                //但现在使用System.setOut(ps)将打印输出窗口改成了由ps指定的文件里 面,通过这样设置以后,打印输出时都会在指定的文件内打印输出 
                //在这里将打印输出窗口设置到了log.txt这个文件里面,所以打印出来的内容会 在log.txt这个文件里面看到 
            }
            for(char c=0;c<=1000;c++){
                System.out.print(c+"\t");//把世界各国的文字打印到log.txt这个文件 中去
            } 
           }catch(Exception e){
            e.printStackTrace();
        } 
    }
}

8.5、Object(对象流)

直接将Object 写入或读出

  • transient关键字:透明的,用它来修饰的成员变量在序列化的时候不予考虑,也就是当成不存在。

  • serializable接口

  • externaliazble接口

import java.io.*;
public class TestObjectIo { 
    public static void main(String args[]) {
        T t = new T();
        t.k = 8;// 把k的值修改为8 
        try {
            FileOutputStream fos = new FileOutputStream( "E:\\TestObjectIo.txt"); 
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            // ObjectOutputStream流专门用来处理Object的,在fos流的外面套接 ObjectOutputStream流就可以直接把一个Object写进去
            oos.writeObject(t);// 直接把一个t对象写入到指定的文件里面 
            oos.flush();
            oos.close();
            FileInputStream fis = new FileInputStream( "E:\\TestObjectIo.txt"); 
            ObjectInputStream ois = new ObjectInputStream(fis); 
            // ObjectInputStream专门用来读一个Object的
            T tRead = (T) ois.readObject();
            // 直接把文件里面的内容全部读取出来然后分解成一个Object对象,并使用强制转换 成指定类型T 
            System.out.print(tRead.i + "\t" + tRead.j + "\t" + tRead.d + "\t" + tRead.k); ois.close();
        } catch (Exception e) {
            e.printStackTrace(); 
        }
    }
}
/*
* 凡是要将一个类的对象序列化成一个字节流就必须实现Serializable接口 
* Serializable接口中没有定义方法,Serializable接口是一个标记性接口,用来给类作标记, 只是起到一个标记作用。
* 这个标记是给编译器看的,编译器看到这个标记之后就可以知道这个类可以被序列化 如果想把某个 类的对象序列化,就必须得实现Serializable接口
*/
class T implements Serializable {
    // Serializable的意思是可以被序列化的 
    int i = 10;
    int j = 9; 
    double d = 2.3;
    int k = 15; 
    // transient int k = 15;
    // 在声明变量时如果加上transient关键字,那么这个变量就会被当作是透明的,即不存在。 }

直接实现Serializable接口的类是JDK自动把这个类的对象序列化,而如果实现public interface Externalizable extends Serializable的类则可以自己控制对象的序列化,建议能让JDK自己控制序列化的就不要让自己去控制


9、总结

标签:读取,int,System,IOException,IO,out,字节
来源: https://www.cnblogs.com/cherish-0/p/16579573.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有