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

目录
相关文章
|
1月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
2月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
6天前
|
安全 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版)
|
16天前
|
数据采集 Java 数据挖掘
Java IO异常处理:在Web爬虫开发中的实践
Java IO异常处理:在Web爬虫开发中的实践
|
30天前
|
Java 数据处理
Java IO 接口(Input)究竟隐藏着怎样的神秘用法?快来一探究竟,解锁高效编程新境界!
【8月更文挑战第22天】Java的输入输出(IO)操作至关重要,它支持从多种来源读取数据,如文件、网络等。常用输入流包括`FileInputStream`,适用于按字节读取文件;结合`BufferedInputStream`可提升读取效率。此外,通过`Socket`和相关输入流,还能实现网络数据读取。合理选用这些流能有效支持程序的数据处理需求。
25 2
|
1月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
1月前
|
缓存 Java
【IO面试题 一】、介绍一下Java中的IO流
Java中的IO流是对数据输入输出操作的抽象,分为输入流和输出流,字节流和字符流,节点流和处理流,提供了多种类支持不同数据源和操作,如文件流、数组流、管道流、字符串流、缓冲流、转换流、对象流、打印流、推回输入流和数据流等。
【IO面试题 一】、介绍一下Java中的IO流
|
1月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
28 2
|
1月前
|
Java Android开发
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
95 1
|
1月前
|
存储 缓存 Java
15 Java IO流(File类+IO流+字节流+字符流+字节编码)
15 Java IO流(File类+IO流+字节流+字符流+字节编码)
42 3