Java中IO流的理解与简单使用(三)

简介: Java中IO流的理解与简单使用(三)

3.缓冲流


* 为了提高数据读写的速度 , Java API 提供了带缓冲功能的流类,在使用这些流类 时,会创建一个内部缓冲区数组,缺省使用 8192 个字节 (8Kb) 的缓冲区 。

*缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为:

BufferedInputStream 和 BufferedOutputStream

BufferedReader 和 BufferedWriter


b0d7f54e7012fd1f5e7c0ccd3bfd9f24_e7c200db830b4a34ac27581d5e50966f.png


3645bc27db39dd52d5f0ce13231e7211_51882c915448481a80672c2f4a6deac1.png


/*
    实现非文本文件的复制
    使用BufferedInputStream,BufferedOutputStream
     */
    @Test
    public void BufferedStreamTest() {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //1.造文件
            File srcFile = new File("pucture.jpg");
            File destFile = new File("pucture3.jpg");
            //2.造流
            //2.1造节点流
            FileInputStream fis = new FileInputStream(srcFile);
            FileOutputStream fos = new FileOutputStream(destFile);
            //2.2造缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            //3.复制的细节:读取、写入
            byte[] buffer = new byte[10];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            //4.资源关闭
            //要求:先关闭外层的流,再关闭内层的流
            //说明:关闭外层流的同时,内层流也会自动的进行关闭
//        fos.close();
//        fis.close();
        }
    }
//********************************************
/*
    使用BufferedReader和BufferedWriter
     */
    @Test
    public void testBufferedReaderBufferedWriter(){
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            //创建文件和对应的流
            br = new BufferedReader(new FileReader(new File("hello.txt")));
            bw = new BufferedWriter(new FileWriter(new File("hello3.txt")));
            //读写操作
            //方式一:使用char[]数组
//            char[] cbuf = new char[1024];
//            int len;
//            while ((len = br.read(cbuf)) != -1){
//                bw.write(cbuf,0,len);
//                //bw.flush();
//            }
            //方式二:使用String
            String data;
            while ((data = br.readLine()) != null){
                //方法一:
//                bw.write(data + "\n");//data不包含换行符
                //方法二:
                bw.write(data);;//data不包含换行符
                bw.newLine();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //关闭资源
            if (bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }


4.转换流


e84f311cfd8229276d44f0a07c498d27_c5ffffad4895443c85eb14f0193c3f7c.png

a57cb5145ae1e8d8d6306d2d5d87ee2e_b89d7f32a2284cf78cfa6de407aa1946.png

4d81acd138903bedb0e15afb33da1d7d_c2b05cc286934c4794ba01677b0ce96b.png

7cd3648f6602c42f1b4c6e1cbfcdf712_05da1057c0d842599744af2a2f8b1b95.png


/*
    此时处理异常仍然应该使用try-catch-finally
     InputStreamReader的使用,实现字节的输入流到字符输入与流的转换
    将字符集为utf-8的txt文件,改成字符集为gbk的txt文件
     */
    @Test
    public void test2() throws IOException {
        //1.造文件、造流
        File file1 = new File("dbcp.txt");
        File file2 = new File("dbcp_gbk.txt");
        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);
        InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
        //2.读写过程
        char[] cbuf = new char[20];
        int len;
        while ((len = isr.read(cbuf)) != -1){
            osw.write(cbuf,0,len);
        }
        //3.关闭资源
        isr.close();
        osw.close();
    }


补充:字符编码的说明


97fad8cbdd6aaed79f0a2792a4d99b5b_851953bf1ab54a64b8aaac726badc42b.png


34b1e90049bd74da087a8c43cab913cb_0ee7458cff7d4ea49298b646f6c4f01b.png


5.其他流的使用


1.标准的输入、输出流

2.打印流

3.数据流

①输入输出流


37a8344764434f056ab7aacadd0f147d_84573f2c09db47b88139b4a13fac1dbe.png


/*
    1.标准的输入、输出流
    1.1
    System.in:标准的输入流,默认从键盘输入(字节流)
    System.out:标准的输出流,默认从控制台输出
    1.2
    System类的setIn(InputStream is) / setOut(printStream)方式指定输入和输出的流
    1.3练习
    从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续
    进行输入操作,直至当输入“e”或者“exit”时,退出程序。
   方法一:使用Scanner实现,调用next()返回一个字符串
   方法二:使用System.in实现 ----->  转换流 -------> bufferedReader的readLine()
     */
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            InputStreamReader isr = new InputStreamReader(System.in);
            br = new BufferedReader(isr);
            while (true){
                System.out.println("请输入字符串:");
                String data = br.readLine();
                if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){
                    System.out.println("程序结束");
                    break;
                }
                String upperCase = data.toUpperCase();
                System.out.println(upperCase);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }



②打印流


b8a488011d3910dd06073e3139d9d6f2_18be9453dbc64775a860ddea780ca9e8.png


/*
    2.打印流:PrintStream和PrintWriter
    2.1提供了一系列重载的print()和println()
    2.2练习:
     */
    @Test
    public void test2(){
        PrintStream ps = null;
        try {
            FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
            ps = new PrintStream(fos, true);
            if (ps != null) {// 把标准输出流(控制台输出)改成文件
                System.setOut(ps);
            }
            for (int i = 0; i <= 255; i++) { // 输出ASCII字符
                System.out.print((char) i);
                if (i % 50 == 0) { // 每50个数据一行
                    System.out.println(); // 换行
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                ps.close();
            }
        }
    }



③数据流


2c80e4868183a9d0b9dfcb12d02e00eb_4314be9300cd40dfb95444d4f9e86a08.png



DataOutputStream dos = null;
try { // 创建连接到指定文件的数据输出流对象
dos = new DataOutputStream(new FileOutputStream("destData.dat"));
dos.writeUTF("我爱北京天安门"); // 写UTF字符串
dos.writeBoolean(false); // 写入布尔值
dos.writeLong(1234567890L); // 写入长整数
System.out.println("写文件成功!");
} catch (IOException e) {
e.printStackTrace();
} finally { // 关闭流对象
try {
if (dos != null) {
// 关闭过滤流时,会自动关闭它包装的底层节点流
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}


6.对象流


bfd82a90789aea7ee5a7eb75044626f1_44faf609e77545f18195b8c8a662de18.png

bdef591513f0bcd1aa574ebdef9a7a04_d4ac8984aba34444b9c5b7f87aba357c.png


8a6d8f237b8c82d236ffc7c9548e1681_e10441de5b6243f09b702df112c6465f.png



注意:


①序列化的过程:将内存中的java对象保存到磁盘中或通过网络传输出去


②一个类可序列化的前提


1.需要实现接口Serializable

2.需要当前类提供一个全局常量:serialVersionUID

3.除了当前的类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。         (默认情况下,基本数据和String类型是可序列化的)


ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt"));
Person p = new Person("韩梅梅", 18, "中华大街", new Pet());
oos.writeObject(p);
oos.flush();
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt"));
Person p1 = (Person)ois.readObject();
System.out.println(p1.toString());
ois.close();


7.随机存取文件流


f39a4202dbcb2efbdd0ce9f1664aa22d_d9f65c4869d4412e99296f5a337376e6.png


7e2b1b158bb4c9c611412920df8d926a_32a6198219834b0ba76674338db61476.png


我们可以用 RandomAccessFile 这个类,来实现一个 多线程断点下载 的功能,

用过下载工具的朋友们都知道,下载前都会建立 两个临时文件 ,一个是与

被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次

暂停的时候,都会保存上一次的指针,然后断点下载的时候,会继续从上

一次的地方下载,从而实现断点下载或上传的功能,有兴趣的朋友们可以

自己实现下。


@Test
    public void test1(){
        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            raf1 = new RandomAccessFile(new File("pucture.jpg"),"r");
            raf2 = new RandomAccessFile(new File("pucture1.jpg"),"rw");
            byte[] buffer = new byte[1024];
            int len;
            while ((len = raf1.read(buffer)) != -1) {
                raf2.write(buffer,0,len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (raf1 != null){
                try {
                    raf1.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (raf2 != null){
                try {
                    raf2.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    @Test
    public void test2() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
        raf1.seek(3);//将指针调到角标为3的位置
        raf1.write("xyz".getBytes());
        raf1.close();
    }
    /*
    使用RandomAccessFile实现数据插入效果
    */
    @Test
    public void test3() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
        raf1.seek(3);//将指针调到角标为3的位置
        //保存指针3后面的所有数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while ((len = raf1.read(buffer)) != -1){
            builder.append(new String(buffer,0,len));
        }
        raf1.seek(3);//调回指针写入xyz
        raf1.write("xyz".getBytes());
        //将StringBuilder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());
        raf1.close();
    }


8.NIO.2中Path、Paths、Files类的使用


a7875c01cc4709b72d78beb17681c286_2cf57c60f377440f94a07ea11bc63944.png


0321bbf75f0a1b1b681d7fe6b337213d_585b84bb238e4bd1a0cf202a36f7691c.png

 

d96ad4a333fe74ae88b2f4f1f3c651ae_7ef7baae82144b259a0f0bb104ce243d.png


986038e63a48b4774eeba508f0ed6342_8eabbc8aa43b473fba1a62b94081e6b4.png

8eb2e56efd8978392159f09308259d69_b085d734d3dd465b8074388f54c39243.png


06ffbb9c6cee76c3ef16e448fdcb7719_655787aa9e85483ca5335de96da0f32d.png


8681d8b7882c02bd54d3df23879d6bbe_a462d33c3166414d8a08e2cae9a313b5.png

目录
相关文章
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
67 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
1月前
|
Java 数据处理 开发者
揭秘Java IO流:字节流与字符流的神秘面纱!
揭秘Java IO流:字节流与字符流的神秘面纱!
35 1
|
1月前
|
自然语言处理 Java 数据处理
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
74 1
|
28天前
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
43 0
|
2月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
|
1月前
|
存储 Java 程序员
【Java】文件IO
【Java】文件IO
35 0
|
2月前
|
数据采集 Java 数据挖掘
Java IO异常处理:在Web爬虫开发中的实践
Java IO异常处理:在Web爬虫开发中的实践
|
3月前
|
Java 数据处理
Java IO 接口(Input)究竟隐藏着怎样的神秘用法?快来一探究竟,解锁高效编程新境界!
【8月更文挑战第22天】Java的输入输出(IO)操作至关重要,它支持从多种来源读取数据,如文件、网络等。常用输入流包括`FileInputStream`,适用于按字节读取文件;结合`BufferedInputStream`可提升读取效率。此外,通过`Socket`和相关输入流,还能实现网络数据读取。合理选用这些流能有效支持程序的数据处理需求。
46 2