博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java IO(二)
阅读量:5805 次
发布时间:2019-06-18

本文共 15211 字,大约阅读时间需要 50 分钟。

   字节流

   字符流:

  1. FileReader
  2. FileWriter
  3. BufferedReader
  4. BufferedWriter

   字节流:

  1. FileInputStream 
  2. FileOutputStream
  3. BufferedInputStream 
  4. BufferedOutputStream

   想要操作图片数据,这时就要用到字节流。

   示例代码如下:

import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class FileOutputStreamDemo0 {    public static void main(String[] args) throws IOException {        //writeFile();        //readFile();                //readFile_2();                readFile_3();    }        public static void readFile_3() throws IOException {        FileInputStream fis = new FileInputStream("fos.txt");                //int num = fis.available();                byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区,不用在循环了。不过慎用!!!                fis.read(buf);                //System.out.println("num = " + num);        System.out.println(new String(buf));                fis.close();    }        public static void readFile_2() throws IOException {        FileInputStream fis = new FileInputStream("fos.txt");                byte[] buf = new byte[1024];//还是建议使用1024的整数倍开辟字节数组                int len = 0;                while((len = fis.read(buf)) != -1) {            System.out.println(new String(buf, 0, len));        }                fis.close();    }        public static void readFile() throws IOException {        FileInputStream fis = new FileInputStream("fos.txt");                int ch = 0;                while((ch = fis.read()) != -1) {            System.out.println((char) ch);        }                fis.close();    }        public static void writeFile() throws IOException {        FileOutputStream fos = new FileOutputStream("fos.txt");                fos.write("abcde".getBytes());                fos.close();    }}

   练习1:复制一个图片。

   思路:

  1. 用字节读取流对象和图片关联。
  2. 用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
  3. 通过循环读写,完成数据的存储。
  4. 关闭资源。

   代码:

import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class CopyPic {    public static void main(String[] args) {        FileOutputStream fos = null;        FileInputStream fis = null;                try {            fos = new FileOutputStream("E:\\MyJava\\workspace\\IO_Project\\Krystal.jpg");            fis = new FileInputStream("D:\\Krystal.jpg");                        byte[] buf = new byte[1024];                        int len = 0;                        while((len = fis.read(buf)) != -1) {                fos.write(buf, 0, len);            }        } catch (IOException e) {            throw new RuntimeException("复制失败!");        } finally {            try {                if(fis != null)                     fis.close();            } catch (IOException e) {                throw new RuntimeException("读取关闭失败!");            }            try {                if(fos != null)                     fos.close();            } catch (IOException e) {                throw new RuntimeException("写入关闭失败!");            }        }    }}

   练习2:复制一个MP3文件。

   通过缓冲区(BufferedOutputStream/BufferedInputStream),演示MP3的复制。

   代码:

import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class CopyMp3 {    public static void main(String[] args) throws IOException {        long start = System.currentTimeMillis();        copy_2();        long end = System.currentTimeMillis();        System.out.println((end - start) + "毫秒");    }    /*     * 通过字节流的缓冲区完成复制     */    public static void copy_1() throws IOException {        BufferedInputStream bufis = new BufferedInputStream(                new FileInputStream("E:\\KuGou\\Temp\\滨琦步 - 犬夜叉主题曲.mp3"));                BufferedOutputStream bufos = new BufferedOutputStream(                new FileOutputStream("E:\\MyJava\\workspace\\IO_Project\\滨琦步 - 犬夜叉主题曲.mp3"));                int by = 0;                while((by = bufis.read()) != -1) {            bufos.write(by);        }                bufis.close();        bufos.close();    }    }

   练习3:自定义一个类模拟BufferedInputStream,完成一个MP3文件的复制。

   分析:

mp3是由二进制数据组成的:11111111-1110000000000000000000101010110111010111010010110001问题:自定义的myRead()函数为什么会返回int类型,而不直接返回byte类型呢?分析:byte: -1  ----> int: -111111111(-1)提升为11111111 11111111 11111111 11111111(-1)11111111(-1)--->提升为一个int类型,那还不是-1吗?是-1的原因是因为在8个1前面补的都是1导致的。那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。怎么补0呢?    11111111 11111111 11111111 11111111&   00000000 00000000 00000000 11111111------------------------------------------    00000000 00000000 00000000 11111111    所以应把11111111(-1)提升为00000000 00000000 00000000 11111111(255),避免返回-1这种情况

   代码:

import java.io.BufferedOutputStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;class MyBufferedInputStream {    private InputStream in;    private byte[] buf = new byte[1024 * 4];    private int pos = 0, count = 0;        MyBufferedInputStream(InputStream in) {        this.in = in;    }          /*     * 一次读一个字节,从缓冲区(字节数组)获取。     */    public int myRead() throws IOException {        /*         * 通过in对象读取硬盘上数据,并存储到buf中。         */        if(count == 0) {            count = in.read(buf);            if(count < 0)                return -1;            pos = 0;            byte b = buf[pos];            count--;            pos++;            return b & 255;        } else if(count > 0) {            byte b = buf[pos];            count--;            pos++;            return b & 0xff;        }        return -1;    }        public void myClose() throws IOException {        in.close();    }}public class MyBufferedInputStreamDemo {    public static void main(String[] args) throws IOException {        long start = System.currentTimeMillis();        copy_2();        long end = System.currentTimeMillis();        System.out.println((end - start) + "毫秒");    }        public static void copy_2() throws IOException {        MyBufferedInputStream bufis = new MyBufferedInputStream(                new FileInputStream("E:\\KuGou\\Temp\\滨琦步 - 犬夜叉主题曲.mp3"));                BufferedOutputStream bufos = new BufferedOutputStream(                new FileOutputStream("E:\\MyJava\\workspace\\IO_Project\\滨琦步 - 犬夜叉主题曲_2.mp3"));                int by = 0;                //System.out.println("第一个字节:" + bufis.myRead());//第一个字节:-1,因为读到了连续的11111111                while((by = bufis.myRead()) != -1) {            bufos.write(by);        }                bufis.myClose();        bufos.close();    }}

 

   System类对IO的支持

   读取键盘录入。

   System.out:对应的是标准输出设备,控制台。

   System.in:对应的是标准输入设备,键盘。

   例,需求:通过键盘录入数据。当录入一行数据后,就将该行数据进行打印。如果录入的数据是over,那么录入停止。

   代码:

import java.io.IOException;import java.io.InputStream;public class ReadIn {    public static void main(String[] args) throws IOException {        InputStream in = System.in;        StringBuilder sb = new StringBuilder();        while(true) {            int ch = in.read();            if(ch == '\r')                continue;            if(ch == '\n') {                String s = sb.toString();                if("over".equals(s))                    break;                System.out.println(s.toUpperCase());                sb.delete(0, sb.length());//清空缓冲区            } else {                sb.append((char) ch);            }                    }                //System.out.println('\r' + 0);//13        //System.out.println('\n' + 0);//10        /*        int by = in.read();        int by1 = in.read();        int by2 = in.read();                System.out.println(by);        System.out.println(by1);        System.out.println(by2);        */    }}

   通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。也就是readLine()方法。

   能不能直接使用readLine()方法来完成键盘录入的一行数据的读取呢?

   readLine()方法是字符流BufferedReader类中的方法,而键盘录入的read()方法是字节流InputStream的方法,那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine()方法呢?

   此时就需要用到转换流。

   转换流:

  1. InputStreamReader字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集(GBK)
  2. OutputStreamWriter字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。 

   上例优化之后的代码为:

import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;public class TransStreamDemo0 {    public static void main(String[] args) throws IOException {        /*         * 获取键盘录入对象。         */        //InputStream in = System.in;                /*         * 将字节流对象转成字符流对象,使用转换流——InputStreamReader         */        //InputStreamReader isr = new InputStreamReader(in);                /*         * 为了提高效率,将字符流进行缓冲区技术高效操作,使用BufferedReader         */        //BufferedReader bufr = new BufferedReader(isr);        /*         * 简写格式,键盘录入最常见写法         */        BufferedReader bufr =                 new BufferedReader(new InputStreamReader(System.in));                //OutputStream out = System.out;//屏幕输出        /*         * 字符流输出对象转换成字节流输出对象         */        //OutputStreamWriter osw = new OutputStreamWriter(out);                //BufferedWriter bufw = new BufferedWriter(osw);        /*         * 简写格式         */        BufferedWriter bufw =                 new BufferedWriter(new OutputStreamWriter(System.out));                String str = null;        while((str = bufr.readLine()) != null) {            if("over".equals(str))                break;            //System.out.println(str.toUpperCase());            bufw.write(str.toUpperCase());            bufw.newLine();            bufw.flush();        }        bufw.close();//并没有写bufr.close();是因为此程序一结束掉,就给关闭了。    }}

   

   流操作的基本规律

   最痛苦的就是流对象有很多,不知道该用哪一个。

   通过三个明确来完成:

  1、明确源和目的。

    源:输入流。InputStream Reader

    目的:输出流。OutputStream Writer

  2、操作的数据是否是纯文本。

    是:字符流。

    不是:字节流。

  3、当体系明确后,在明确要使用哪个具体的对象。

    通过设备来进行区分:

    源设备:内存、硬盘、键盘。

    目的设备:内存、硬盘、控制台。

   例1、需求:将一个文本文件中的数据存储到另一个文件中。(复制文件)

  分析:

    源:因为是源,所以使用读取流。InputStream Reader

    是不是操作文本文件?

    是!这时就可以选择Reader,这样体系就明确了。

    接下来要明确要使用该体系中的那个对象?

    明确设备:硬盘上的一个文件。Reader体系中可以操作文件的对象是FileReader。

    是否需要提高效率?是!加入Reader体系中的缓冲区BufferedReader。

FileReader fr = new FileReader("a.txt");BufferedReader bufr = new BufferedReader(fr);

    目的:OutputStream Writer

    目的是否是纯文本?是!Writer。

    设备:硬盘上的一个文件。

    Writer体系中可以操作文件的对象是FileWriter。

    是否需要提高效率?是!加入Reader体系中的缓冲区BufferedWriter。

FileWriter fw = new FileWriter("b.txt");BufferedWriter bufw = new BufferedWriter(fr);

   练习:将一个图片文件中的数据存储到另一个文件中。(复制文件)

   代码:

/* * 练习:将一个图片文件中的数据存储到另一个文件中。(复制文件) */import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class test0 {    public static void main(String[] args) {        FileInputStream fis = null;        FileOutputStream fos = null;        BufferedInputStream bis = null;        BufferedOutputStream bos = null;        byte[] by = new byte[1024];        int len = 0;        try {            fis = new FileInputStream("d:\\Krystal.jpg");            bis = new BufferedInputStream(fis);                        fos = new FileOutputStream("d:\\java\\io123\\Krystal.jpg");            bos = new BufferedOutputStream(fos);                        while((len = bis.read(by)) != -1) {                bos.write(by, 0, len);            }        }  catch (IOException e) {            throw new RuntimeException("图片复制失败!");        } finally {            try {                if(bis != null)                     bis.close();            } catch (IOException e) {                throw new RuntimeException("关闭读取流失败!");            }            try {                if(bos != null)                     bos.close();            } catch (IOException e) {                throw new RuntimeException("关闭写入流失败!");            }        }    }}

   例2、需求:将键盘录入的数据保存到一个文件中。

  分析:

    这个需求中有源和目的都存在。那么分别分析

    源:InputStream Reader

    是不是纯文本?是!Reader

    设备:键盘。对应的对象是System.in。

    不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘的文本数据方便,转成字符流,按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成字符流Reader。用到了Reader体系中的转换流,InputStreamReader

InputStreamReader isr = new InputStreamReader(System.in);

    需要提高效率吗?需要!BufferedReader 

BufferedReader bufr = new BufferedReader(isr);

    目的:OutputStream Writer

    是不是纯文本?是!Writer

    设备:硬盘上的一个文件。使用FileWriter。

FileWriter fw = new FileWriter("c.txt");

    需要提高效率吗?需要!BufferedWriter

BufferedWriter bufw = new BufferedWriter(fw);

  扩展一下,想要把录入的数据按照指定的编码表(UTF-8),将数据存到文件中,怎么办呢?

  分析:

    目的:OutputStream Writer

    是不是纯文本?是!Writer

    设备:硬盘上的一个文件。使用FileWriter。但是FileWriter是使用的默认编码表(GBK)

    但是存储时,需要加入指定的编码表(UTF-8),而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStreamWriter。而该转换流对象要接收一个字节输出流,而且还可以操作文件的字节输出流,FileOutputStream。

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"), "UTF-8");

    需要提高效率吗?需要!BufferedWriter

BufferedWriter bufw = new BufferedWriter(osw);

  所以,记住,转换流什么时候使用?字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流

   练习:将一个文本数据打印在控制台上。

   代码:

/* * 练习:将一个文本数据打印在控制台上。 */import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.IOException;import java.io.OutputStreamWriter;public class test1 {    public static void main(String[] args) {        BufferedReader br = null;        BufferedWriter bw = null;        String line = null;                        try {            br = new BufferedReader(new FileReader("d:\\java\\ArrayTool.java"));            bw = new BufferedWriter(new OutputStreamWriter(System.out));            while((line = br.readLine()) != null) {                bw.write(line);                bw.newLine();                bw.flush();            }        } catch (IOException e) {            throw new RuntimeException("读取文件失败");        } finally {            try {                if(br != null)                     br.close();            } catch (IOException e) {                throw new RuntimeException("读取流关闭失败");            }            try {                if(bw != null)                    bw.close();            } catch (IOException e) {                throw new RuntimeException("写入流关闭失败");            }        }            }}

 

   异常的日志信息

 log4j:记录日志信息的一个工具。

   示例代码如下:

import java.io.FileNotFoundException;import java.io.PrintStream;import java.text.SimpleDateFormat;import java.util.Date;public class ExceptionInfo {    public static void main(String[] args) {                try {            int[] arr = new int[2];            System.out.println(arr[3]);        } catch (Exception e) {            try {                Date d = new Date();                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");                String s = sdf.format(d);                PrintStream ps = new PrintStream("exception.log");                //ps.write(d.toString().getBytes());                ps.println(s);                System.setOut(ps);            } catch (FileNotFoundException e1) {                throw new RuntimeException("日志文件创建失败!");            }            e.printStackTrace(System.out);            //e.printStackTrace(new PrintStream("ex.txt"));        }    }}

 

   系统信息

   示例代码如下:

import java.io.FileNotFoundException;import java.io.PrintStream;import java.util.Properties;public class SystemInfo {    public static void main(String[] args) throws FileNotFoundException {        Properties pro = System.getProperties();        //System.out.println(pro);        pro.list(new PrintStream("sysinfo.txt"));    }}

   通过sysinfo.txt文本文件可以知道平台默认的字符集,即默认字符编码是GBK

   

 

转载于:https://www.cnblogs.com/yerenyuan/p/5269424.html

你可能感兴趣的文章
Android 侦听应用(Package)变化的方法侦听广播
查看>>
jfrog artifactory jenkins pipeline 集成
查看>>
node.js版本管理
查看>>
Spring 官方教程:使用 Restdocs 创建 API 文档
查看>>
Guava Cache
查看>>
java.lang.NoClassDefFoundError: org/apache/ibatis/mapping/DatabaseIdProvider
查看>>
Clipboard.js : 移动端浏览器实现网页内容复制
查看>>
并发的学习与使用
查看>>
不能下载程序
查看>>
mysql开启慢查询日志
查看>>
070——VUE中vuex之使用getters计算每一件购物车中商品的总价
查看>>
在 Swift 專案中使用 Javascript:編寫一個將 Markdown 轉為 HTML 的編輯器
查看>>
CSS :befor :after 伪元素的妙用
查看>>
机器学习 — 推荐系统
查看>>
如何辨别真假红菇
查看>>
JXL生成Excel,并提供下载(1:生成Excel)
查看>>
大量用户升级iPhone3.0系统导致苹果服务器故障
查看>>
Gac代码库分析(1)
查看>>
IBM高级工程师,谷歌等国际知名公司工程师撰写Android开发教程合集
查看>>
poj 图论题目列表 [转]
查看>>