• JAVA中文件的读写 I/O 输入输出流


    主要内容

    1.编码问题

    2.File类的使用

    3.RandomAccessFile的使用

    4.I/O 输入输出流

    编码问题:

     1 import java.io.UnsupportedEncodingException;
     2 
     3 public class 编码问题 {
     4     public static void main(String[] args) {
     5         // 我们项目的默认编码是GBK
     6         String s = "测试 ABC";
     7         byte[] byte1 = s.getBytes();// 转换成的字节序列用的是项目默认的编码gbk
     8         for (byte b : byte1) {
     9             // 1 byte = 8 位 //toHexString这个函数是把字节(转换成了Int)以16进制的方式显示
    10             System.out.print(Integer.toHexString(b & 0xff) + " ");// &
    11                                                                     // 0xff是为了把前面的24个0去掉只留下后八位
    12         }
    13 
    14         try {
    15             // 也可以转换成指定的编码
    16             byte[] bytes1 = s.getBytes("gbk");
    17             System.out.println(new String(bytes1));
    18         } catch (UnsupportedEncodingException e) {
    19             // TODO Auto-generated catch block
    20             e.printStackTrace();
    21         }
    22         /**
    23          * gbk编码: 中文占用两个字节,英文占用一个字节 utf-8编码:中文占用三个字节,英文占用一个字节
    24          * java是双字节编码,是utf-16be编码 utf-16be编码:中文占用两个字节,英文占用两个字节
    25          * 当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码
    26          */
    27         try {
    28             byte[] byte2 = s.getBytes("utf-16be");
    29             String s2 = new String(byte2, "utf-16be");
    30             System.out.println(s2);
    31         } catch (UnsupportedEncodingException e) {
    32             // TODO Auto-generated catch block
    33             e.printStackTrace();
    34         }
    35         /**
    36          * 文本文件就是字节序列,可以是任意编码的字节序列
    37          * 如果我们在中文机器上直接创建文本文件,那么该文件只认识ANSI编码(例如直接在电脑中创建文本文件)
    38          */
    39 
    40         /**
    41          * byte转int的时候为什么非要先&0xff计算出来才是正确答案?
    42          * 首先,java中的二进制采用的是补码形式,并非原码或反码,这3个概念要搞清楚;
    43          * 其次,byte占8位,int占32位,将byte强制转换为int型时,如果没有做 &
    44          * 0xff运算,且byte对应的值为负数的话,就会对高位3个字节进行补位,这样就有可能出现补位误差的错误。
    45          * 举例来说,byte型的-1,其二进制(补码)为11111111(即0xff),转换成int型,值也应该为-1,但经过补位后,
    46          * 得到的二进制为11111111111111111111111111111111(即0xffffffff),这就不是-1了,对吧?
    47          * 而0xff默认是int型,所以,一个byte跟0xff相与,会先将那个byte转化成int型运算,这样,结果中的高位3个字节就总会被清0,
    48          * 于是结果就是我们想要的了~
    49          */
    50 
    51     }
    52 
    53 }
    View Code

    File类的使用:

    JAVA.io.File类用于表示文件(目录)
    File类只用于表示文件( 目录)的信息(名称、大小等),不能用于文件内容的访问
    File类的常用API:
    1.创建File对象:File file=new File(String path);注意:File.seperater();获取系统分隔符,如:”“.
    2.boolean file.exists();是否存在.
    3.file.mkdir();或者file.mkdirs();创建目录或多级目录。
    4.file.isDirectory()或者file.isFile()判断是否是目录或者是否是文件。
    5.file.delete();删除文件或目录。
    6.file.createNewFile();创建新文件。
    7.file.getName()获取文件名称或目录绝对路径。
    8.file.getAbsolutePath()获取绝对路径。
    9.file.getParent();获取父级绝对路径。
    10.file.getSize();获取文件大小。
    11.file.getFormat();获取文件格式名。
     1 import java.io.File;
     2 import java.io.IOException;
     3 
     4 public class FileDemo {
     5 
     6     /**
     7      * @param args
     8      */
     9     public static void main(String[] args) {
    10         // 了解构造函数的情况 查帮助ALT+/
    11         File file = new File("E:\javaio\imooc");
    12         // 判断文件/文件夹是否存在
    13         // System.out.println(file.exists());
    14         if (!file.exists())
    15             file.mkdir(); // file.mkdirs()如果文件不存在,直接创建文件夹
    16         // mkdir创建的一级目录,如果需要创建多级目录可以使用mkdirs()
    17         else
    18             file.delete();
    19 
    20         // 是否是一个目录 如果是目录返回true,如果不是目录or目录不存在返回的是false
    21         System.out.println(file.isDirectory());
    22         // 是否是一个文件
    23         System.out.println(file.isFile());
    24 
    25         // File file2 = new File("e:\javaio\日记1.txt");
    26         File file2 = new File("e:\javaio", "日记1.txt");
    27         if (!file2.exists())
    28             try {
    29                 file2.createNewFile();
    30             } catch (IOException e) {
    31                 // TODO Auto-generated catch block
    32                 e.printStackTrace();
    33             }
    34         else
    35             file2.delete();
    36         // 常用的File对象的API
    37         System.out.println(file);// file.toString()的内容
    38         System.out.println(file.getAbsolutePath());
    39         System.out.println(file.getName());
    40         System.out.println(file2.getName());
    41         System.out.println(file.getParent());
    42         System.out.println(file2.getParent());
    43         System.out.println(file.getParentFile().getAbsolutePath());
    44     }
    45 
    46 }
    FileDemo

    遍历目录

     1 import java.io.File;
     2 import java.io.IOException;
     3 
     4 //列出File的一些常用操作比如过滤,遍历等操作
     5 public class FileUtils {
     6     /**
     7      * 列出指定指定目录下(包括其子目录)的所有文件
     8      * 
     9      * @param dir
    10      * @throws IOException
    11      */
    12     public static void listDirectory(File dir) throws IOException {
    13         if (!dir.exists()) {
    14             throw new IllegalArgumentException("目录:" + dir + "不存在");
    15         }
    16         if (!dir.isDirectory()) {
    17             throw new IllegalArgumentException(dir + "不是目录");
    18         }
    19 
    20         // String[] fileNames =
    21         // dir.list();//返回的是字符串数组,list()方法用于列出当前目录下的子目录和文件,直接子的名称,不包含子目录下的内容
    22         // for (String string : fileNames) {
    23         // System.out.println(dir+"\"+string);
    24         // }
    25         //
    26         // 如果要遍历子目录下的内容就需要构造成File对象做递归操作,File提供了直接返回File对象的API
    27         File[] files = dir.listFiles();// 返回的是直接子目录(文件)的抽象
    28         if (files != null && files.length > 0) {// 确定存在子目录
    29             for (File file : files) {
    30                 if (file.isDirectory()) {
    31                     // 递归
    32                     listDirectory(file);
    33                 } else {
    34                     System.out.println(file);
    35                 }
    36             }
    37         }
    38     }
    39 }
    FileUtils

    RandomAccessFile的使用

    RandomAccessFile JAVA提供的对文件内容的访问,既可以读文件,也可以写文件。
    RandomAccessFile支持随机访问文件,可以访问文件的任意位置
    (1)JAVA文件模型
    在硬盘上的文件是byte byte byte存储的,是数据的集合
    (2)打开文件
    有两种模式"rw"(读写) "r"(只读)
    RandomAccessFile raf = new RandomeAccessFile(file,"rw")
    文件指针,打开文件时指针在开头 pointer = 0;
    (3) 写方法
    raf.write(int)--->只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
    提供和很多方法能够一次读写一个基本类型的数据
    (4)读方法
    int b = raf.read()--->读一个字节
    (5)文件读写完成以后一定要关闭(Oracle官方说明)
     1 import java.io.File;
     2 import java.io.IOException;
     3 import java.io.RandomAccessFile;
     4 import java.util.Arrays;
     5 
     6 public class RafDemo {
     7 
     8     /**
     9      * @param args
    10      */
    11     public static void main(String[] args) throws IOException {
    12         File demo = new File("demo");
    13         if (!demo.exists())
    14             demo.mkdir();
    15         File file = new File(demo, "raf.dat");
    16         if (!file.exists())
    17             file.createNewFile();
    18 
    19         RandomAccessFile raf = new RandomAccessFile(file, "rw");
    20         // 指针的位置
    21         System.out.println(raf.getFilePointer());
    22 
    23         raf.write('A');// 只写了一个字节
    24         System.out.println(raf.getFilePointer());
    25         raf.write('B');
    26 
    27         int i = 0x7fffffff;
    28         // 用write方法每次只能写一个字节,如果要把i写进去就得写4次
    29         raf.write(i >>> 24);// 高8位
    30         raf.write(i >>> 16);
    31         raf.write(i >>> 8);
    32         raf.write(i);
    33         System.out.println(raf.getFilePointer());
    34 
    35         // 可以直接写一个int
    36         raf.writeInt(i);
    37 
    38         String s = "中";
    39         byte[] gbk = s.getBytes("gbk");
    40         raf.write(gbk);
    41         System.out.println(raf.length());
    42 
    43         // 读文件,必须把指针移到头部
    44         raf.seek(0);
    45         // 一次性读取,把文件中的内容都读到字节数组中
    46         byte[] buf = new byte[(int) raf.length()];
    47         raf.read(buf);
    48 
    49         System.out.println(Arrays.toString(buf));
    50         for (byte b : buf) {
    51             System.out.println(Integer.toHexString(b & 0xff) + " ");
    52         }
    53         raf.close();
    54     }
    55 
    56 }
    RafDemo
    import java.io.IOException;
    import java.io.RandomAccessFile;
    
    public class RafReadDemo {
    
        /**
         * @param args
         */
        public static void main(String[] args) throws IOException {
            // TODO Auto-generated method stub
            RandomAccessFile raf = new RandomAccessFile("demo/raf.dat", "r");
            raf.seek(2);
            int i = 0;
            int b = raf.read();// 读取到一个字节
            System.out.println(raf.getFilePointer());
            i = i | (b << 24);
            b = raf.read();
            i = i | (b << 16);
            b = raf.read();
            i = i | (b << 8);
            b = raf.read();
            i = i | b;
            System.out.println(Integer.toHexString(i));
            raf.seek(2);
            i = raf.readInt();
            System.out.println(Integer.toHexString(i));
            raf.close();
        }
    }
    RafReadDemo
    序列化与基本类型序列化
    1)将类型int 转换成byte或将其他数据类型转换成byte的过程叫序列化
    数据---->n byte
    2)反序列化
    将n个byte 转换成一个数据的过程
    nbyte ---> 数据
    3)RandomAccessFile提供基本类型的读写方法,可以将基本类型数据
    序列化到文件或者将文件内容反序列化为数据
     1 import java.io.File;
     2 import java.io.IOException;
     3 import java.io.RandomAccessFile;
     4 public class RandomAccessFileSeriaDemo {
     5 
     6     /**
     7      * @param args
     8      */
     9     public static void main(String[] args) throws IOException {
    10         // TODO Auto-generated method stub
    11         File demo = new File("demo1");
    12         if (!demo.exists())
    13             demo.mkdir();
    14         File file = new File(demo, "raf.dat");
    15         if (!file.exists())
    16             file.createNewFile();
    17         // 打开文件,进行随机读写
    18         RandomAccessFile raf = new RandomAccessFile(file, "rw");
    19         /* 序列化 */
    20         int i = 0x7ffffff;
    21         raf.write(i >>> 24);
    22         raf.write(i >>> 16);
    23         raf.write(i >>> 8);
    24         raf.write(i);
    25         System.out.println(raf.getFilePointer());
    26 
    27         /* 反序列化 */
    28         raf.seek(0);
    29         int b = raf.read();
    30         i = i | (b << 24);
    31         b = raf.read();
    32         i = i | (b << 16);
    33         b = raf.read();
    34         i = i | (b << 8);
    35         b = raf.read();
    36         i = i | b;
    37         System.out.println(Integer.toHexString(i));
    38         raf.close();
    39     }
    40 }
    41 
    42 RandomAccessFileSeriaDemo
    RandomAccessFileSeriaDemo

    I/O 输入输出流

    流的定义:

    流就是程序和设备之间嫁接起来的一根用于数据传输的管道,这个管道上有很多按钮,不同的按钮可以实现不同的功能。

    这根用于数据传输的管道就是流,流就是一根管道

    输入时,程序在源(文件,网络,内存)上打开一个流,然后如图一个一个顺序读。写也一样。

    流的分类和使用:

    四大基本抽象流,文件流,缓冲流,转换流,数据流,Print流,Object流。

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

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

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

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

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

    节点流与处理流:

    节点流可以从一个特定的数据源(节点)读取数据(如:文件,内存)

    处理流是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

    节点流也叫原始流,处理流也叫包裹流。

    流与类的关系:

    如果一个类是用作设备和程序之间的数据传输,则这个类有一个新的名字叫做流

    流一定是类,但类不一定是流

    四大基本流的介绍

    输入流,输出流,字节流,字符流

    InputStream和OutputStream读写数据的单位是一个字节

    Reader和Writer读写数据的单位是一个字符

    在JAVA中一个字符占两个字节

    InputStream,OutputStream,Reader,Writer都是抽象类,或者说都是抽象流,通常我们使用的都是它们的子类,凡是以Stream结尾的都是字节流。

    InputStream 流中的常用方法:

    OutputStream 流中的常用方法:

    Reader 流中的常用方法:

     Writer 流中的常用方法:

     

    文件流

     文件流包括:

    FileInputStream FileOutputStream --字节流

    FileReader FileWriter --字符流

    实例:读取一个文件的内容并将其输出到显示器上,并统计读取的字节个数

     1 /*
     2     利用FileReader流来读取一个文件中的数据,并在显示器上输出!
     3 */
     4 
     5 import java.io.*;
     6 
     7 public class TestFileReader {
     8     public static void main(String[] args) {
     9         FileReader fr = null;
    10 
    11         try {
    12             fr = new FileReader("C:\Documents and Settings\others\桌面\java\TestFileReader.java");
    13             int cnt = 0;
    14             int ch;
    15 
    16             while (-1 != (ch = fr.read())) // 20行
    17             {
    18                 System.out.print((char) ch); // System.out.print(int ch);
    19                                                 // 这是在显示器上输出ch的整数值,所以必须的进行类型转化,我们需要输出的是ch所代表的整数对应的字符
    20                 ++cnt;
    21             }
    22 
    23             System.out.printf("总共从TestFileReader.java文件中读取了%d个字符", cnt);
    24         } catch (FileNotFoundException e) {
    25             System.out.println("找不到文件!");
    26             System.exit(-1);
    27         } catch (IOException e) {
    28             System.out.println("文件读取失败!");
    29             System.exit(-1);
    30         }
    31     }
    32 }
    View Code

    FileInputStream的使用

    FileReader的使用

    字节流与字符流的区别:

    FileInputStream 和FileOutputStream 可以完成所有格式文件的复制

    FileReader和FileWriter只可以完成文本文件的复制,却无法完成其他格式文件的复制

    因为字节是不需要解码和编码的,将字节转化为字符才存在解码和编码的问题

    字节流可以从所有格式的设备中读写数据,但字符流只能从文本格式的设备中读写数据

    实例:编程实现文件的复制

     1 /*
     2     利用FileInputStream 和 FileOutputStream 可以完成所有格式文件的赋值
     3     因为字节是不需要解码和编码的,将字节转化为字符才存在解码的问题
     4     本程序完成了音频文件的复制
     5 */
     6 
     7 import java.io.*;
     8 
     9 public class TestFileInputStreamOutputStreamCopy {
    10     public static void main(String[] args) {
    11         FileInputStream fi = null;
    12         FileOutputStream fo = null;
    13 
    14         try {
    15             fi = new FileInputStream("E:\综艺\歌曲\卡农.mp3");
    16             fo = new FileOutputStream("d:/share/Output.txt"); //使用播放器可正常播放该文件
    17             int ch;
    18 
    19             while (-1 != (ch = fi.read())) {
    20                 fo.write(ch);
    21             }
    22         } catch (FileNotFoundException e) {
    23             System.out.println("文件没有找到!");
    24             System.exit(-1);
    25         } catch (IOException e) {
    26             System.out.println("文件读写错误!");
    27             System.exit(-1);
    28         } finally {
    29             try {
    30                 if (null != fi) {
    31                     fi.close();
    32                     fi = null;
    33                 }
    34                 if (null != fo) {
    35                     fo.close();
    36                     fo = null;
    37                 }
    38             } catch (Exception e) {
    39                 e.printStackTrace();
    40                 System.exit(-1);
    41             }
    42         }
    43 
    44         System.out.println("文件复制成功!");
    45     }
    46 }
    TestFileInputStreamOutputStreamCopy
     1 /*
     2     本程序证明了 FileReader 和 FileWriter 只可以完成文本文件的复制,
     3             却无法完成音频格式文件的复制
     4 */
     5 
     6 import java.io.*;
     7 
     8 public class TestFileReaderWriterCopy {
     9     public static void main(String[] args) {
    10         FileReader fi = null;
    11         FileWriter fo = null;
    12 
    13         try {
    14             fi = new FileReader("E:\综艺\歌曲\卡农.mp3");
    15             fo = new FileWriter("d:/share/Output.txt"); // Output.txt使用播放器打开失败!
    16                                                         // 本程序证明了FileWriter 和
    17                                                         // FileReader
    18                                                         // 无法完成音频文件的复制,实际上FileWriter
    19                                                         // 和 FileReader
    20                                                         // 只能完成文本文件的复制
    21             int ch;
    22 
    23             while (-1 != (ch = fi.read())) {
    24                 fo.write(ch);
    25             }
    26         } catch (FileNotFoundException e) {
    27             System.out.println("文件没有找到!");
    28             System.exit(-1);
    29         } catch (IOException e) {
    30             System.out.println("文件读写错误!");
    31             System.exit(-1);
    32         } finally {
    33             try {
    34                 if (null != fi) {
    35                     fi.close();
    36                     fi = null;
    37                 }
    38                 if (null != fo) {
    39                     fo.close();
    40                     fo = null;
    41                 }
    42             } catch (Exception e) {
    43                 e.printStackTrace();
    44                 System.exit(-1);
    45             }
    46         }
    47 
    48         System.out.println("文件复制成功!");
    49     }
    50 }
    TestFileReaderWriterCopy

    缓冲流

    缓冲流就是带有缓冲区的输入输出流

    缓冲流可以显著的减少我们对IO访问的次数,保护我们的硬盘

    缓冲流本事就是处理流(包裹流),缓冲流必须得依附于节点流(原始流)

    处理流包裹在原始节点流上的流,相当于包裹在管道上的管道

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

    BufferedOutputStream 和 BufferedInputStream

    BufferedOutputStream :带有缓冲的输出流,允许一次向硬盘写入多个字节的数据。

    BufferedInputStream:带缓冲的输入流,允许一次向程序中读入多个字节的数据。

    BufferedOutputStream 和 BufferedInputStream都是包裹流,必须依附于OutputStream和InputStream

    例子:利用BufferedOutputStream 和 BufferedInputStream 完成大容量文件的复制,这远比单纯利用FileInputStream和FileOutputStream要快的多

     1 /*
     2     利用BufferedOutputStream 和 BufferedInputStream完成大容量文件的复制
     3     这远比单纯利用 FileInputStream  和 FileOutputStream 要快得多
     4 
     5     BufferedOutputStream 和 BufferedInputStream 都是包裹流,必须的依附于
     6     InputStream 和 OutputStream 
     7 */
     8 
     9 import java.io.*;
    10 
    11 public class TestBufferedInputStreamOutputStreamCopy {
    12     public static void main(String[] args) {
    13         BufferedOutputStream bos = null;
    14         BufferedInputStream bis = null;
    15 
    16         try {
    17             bos = new BufferedOutputStream(new FileOutputStream("e:/OutputView.txt")); // bos
    18                                                                                         // 输出流有个默认的缓冲区,大小为32个字节
    19 
    20             bis = new BufferedInputStream(new FileInputStream("c:\[高清在线www.66ys.cn]海底总动员DVD中英字幕.rmvb")); // bis
    21                                                                                                             // 输入流有个默认的缓冲区,大小为32个字节
    22             byte[] buf = new byte[1024];
    23             int len = bis.read(buf, 0, 1024); // 一定要注意,这不是从buf中读数据,而是从bis所关联到的D:\综艺\电影\猫和老鼠\CD4.rmvb文件中读取数据,并将读取的数据写入bis自己的默认缓冲区中,然后再将缓冲区的内容写入buf数组中,每次最多向buf数组中写入1024个字节,返回实际写入buf数组的字节个数,如果读到了文件的末尾,无法再向buf数组中写入数据,则返回-1
    24             while (-1 != len) {
    25                 bos.write(buf, 0, len); // 不是写入buf数组,而是将buf数组中下标从0开始的到len-1为止的所有数据写入bos所关联到的"d:/share/OutputView.txt"文件中
    26                 len = bis.read(buf); // bis.read(buf); 等价于 bis.read(buf, 0,
    27                                         // buf.length);
    28             }
    29             bos.flush();
    30             bis.close();
    31             bos.close();
    32         } catch (FileNotFoundException e) {
    33             System.out.println("没有找到文件!");
    34             System.exit(-1);
    35         } catch (IOException e) {
    36             System.out.println("文件读写错误!");
    37             System.exit(-1);
    38         }
    39 
    40         System.out.println("文件复制成功!");
    41     }
    42 }
    TestBufferedInputStreamOutputStreamCopy
     1 /*
     2     本程序读写速度要慢于  "TestBufferedInputStreamOutputStreamCopy.java" 程序
     3     即:
     4     利用BufferedOutputStream 和 BufferedInputStream完成大容量文件的复制
     5     这远比单纯利用 FileInputStream  和 FileOutputStream 要快得多
     6 
     7     BufferedOutputStream 和 BufferedInputStream 都是包裹流,必须的依附于
     8     OutputStream  和 OutputStream 
     9 */
    10 
    11 import java.io.*;
    12 
    13 public class TestBufferedInputStreamOutputStreamCopy_2 {
    14     public static void main(String[] args) {
    15         FileOutputStream bos = null;
    16         FileInputStream bis = null;
    17 
    18         try {
    19             bos = new FileOutputStream("e:/OutputView.txt");
    20             bis = new FileInputStream("c:\[高清在线www.66ys.cn]海底总动员DVD中英字幕.rmvb");
    21 
    22             byte[] buf = new byte[1024];
    23             int len = bis.read(buf, 0, 1024);
    24             while (-1 != len) {
    25                 bos.write(buf, 0, len);
    26                 len = bis.read(buf);
    27             }
    28             bos.flush();
    29             bis.close();
    30             bos.close();
    31         } catch (FileNotFoundException e) {
    32             System.out.println("没有找到文件!");
    33             System.exit(-1);
    34         } catch (IOException e) {
    35             System.out.println("文件读写错误!");
    36             System.exit(-1);
    37         }
    38 
    39         System.out.println("文件复制成功!");
    40     }
    41 }
    TestBufferedInputStreamOutputStreamCopy_2

    一定要注意,bis.read(buf,0,1024);这不是从buf中读数据,而是从bis所关联到的“D:\综艺\电影\猫和老鼠\CD4.rmvb”文件中读取数据,并将读取的数据写入bis自己的默认缓冲区中,然后再将缓冲区的内容写入buf数组中,每次最多向buf数组中写入1024个字节,返回实际写入buf数组的字节个数,如果读到了文件的末尾,无法再向buf数组中写入数据,则返回-1

    BufferedInputStream流中有public int read(byte[] b)方法用来把从当前流关联到的设备中读取出来的数据存入一个byte数组中

    BufferedOutputStream 流中有public int write(byte[] b)方法用来把byte数组中的数据输出来当前流所关联到的设备中

    如果我们希望用BufferedInputStream 和 BufferedOutputStream 完成“将一个设备中的数据导入另一个设备中”,我们就应该定义一个临时的byte类型的数据,用这个临时数组作为输入流和输出流进行交互的中转枢纽。

    BufferedReader 和 BufferedWriter

    实例:利用BufferedReader 和 BufferedWriter完成文本文件的复制

     1 /*
     2     利用 BufferedReader 和 BufferedWriter 完成文本文件的复制
     3 */
     4 import java.io.*;
     5 
     6 public class TestBufferedReaderWriterCopy {
     7     public static void main(String[] args) {
     8         BufferedReader br = null;
     9         BufferedWriter bw = null;
    10 
    11         try {
    12             br = new BufferedReader(
    13                     new FileReader("C:\Documents and Settings\others\桌面\java\TestBufferedReaderWriterCopy.java"));
    14             bw = new BufferedWriter(new FileWriter("d:/share/Writer.txt"));
    15             String str = null;
    16 
    17             while (null != (str = br.readLine())) // br.readLine()读取一行字符,但会将读取的换行符自动丢弃,即返回的String对象中并不包括换行符
    18             {
    19                 bw.write(str);
    20                 bw.newLine(); // 写入一个换行符 这行不能省
    21             }
    22             bw.flush();
    23         } catch (FileNotFoundException e) {
    24             e.printStackTrace();
    25             System.exit(-1);
    26         } catch (IOException e) {
    27             e.printStackTrace();
    28             System.exit(-1);
    29         } finally {
    30             try {
    31                 bw.close();
    32                 br.close();
    33             } catch (IOException e) {
    34                 e.printStackTrace();
    35                 System.exit(-1);
    36             }
    37         }
    38     }
    39 }
    TestBufferedReaderWriterCopy

     

    数据流DataInputStream DataOutputStream

    DataInputStream能够以一种与机器无关的方式,直接从底层字节输入流读取JAVA基本类型和String类型的数据。常用方法包括:

    DataInputStream 是包裹流,必须依附于InputStream

    DataOutputStream能够以一种机器无关的方式,直接将JAVA基本类型和String类型数据写出到其他的字节输出流。常用方法包括:

    DataOutputStream 是包裹流,它必须依附于OutputStream

    数据流实例:

    编程实现将long类型数据写入byte数组,然后再从byte数组中吧该数据读出来{

      *这是Socket编程中经常要完成的功能。

      *因为网络编程中经常要把数据存入byte数组中,然后把byte数组打包成数据包(DatagramPacket),再把数据包经过网络传输到目的机,目的机再从byte数组中把原数值型数据还原回来。

    }

    本程序要使用到:

    DataInputStream 

    DataOutputStream

    ByteArrayInputStream

    ByteArrayOutputStream

     1 /*
     2     功能:把一个long类型的数据写入byte数组中,然后再从byte数组中读取出
     3           这个long类型的数据
     4           
     5           因为网络编程中经常要把数值型数据存入byte数组中然后打包成
     6           DatagramPacket经过网络传输到目的机,目的机再从byte数组中
     7           把原数值型数据还原回来
     8     
     9     目的: ByteArrayOutputStream   DataOutputStream  ByteInputStream DataInputStream 流的使用
    10           记住: DataOutputStream流中的writeLong(long n)是把n变量在内存
    11                   中的二进制代码写入该流所连接到的设备中
    12                   
    13     注意:查API文档得知:
    14             构造  ByteArrayOutputStream 对象时不需要也不能指定缓冲数组,因为缓冲数组默认已经内置好了         
    15               构造  ByteArrayInputStream 对象时必须的指定缓冲数组是谁!
    16 */
    17 
    18 import java.io.*;
    19 
    20 public class TestByteArrayOutputStream1
    21 {
    22     public static void main(String args[]) throws Exception
    23     {
    24         long n = 9876543210L;
    25         ByteArrayOutputStream baos = new ByteArrayOutputStream();  //9行  API:"public ByteArrayOutputStream(): 创建一个新的 byte 数组输出流。缓冲区的容量最初是 32 字节,如有必要可增加其大小。 "
    26                                     //9行代码一旦执行完毕,意味着两点: 1、在内存中生成了一个大小为32个字节的byte数组   2、有一根叫做baos的管道已链接到了该byte数组中,并且可以通过这个管道向该byte数组中写入数据
    27                                     //虽然此时可以通过baos向baos所连接到的在内存中分配好的byte数组中写入数据,但是ByteArrayOutputStream流并没有提供可以直接把long类型数据直接写入ByteArrayOutputStream流所连接到的byte数组中的方法, 简单说我们没法通过baos向baos所连接到的byte数组中写入long类型的数据, 查API文档可以发现: ByteArrayOutputStream流中并没有类似writeLong()这样的方法,但是DataOutputStream流中却有writeLong() writeFloat()等方法
    28         DataOutputStream dos = new DataOutputStream(baos);
    29         
    30         dos.writeLong(n);  //把n变量所代表的10000L在内存中的二进制代码写入dos所依附的baos管道所连接到的内存中的大小为32字节的byte数组中,由运行结果来看,这是二进制写入,既不是把10000L转化为字符'1' '0' '0' '0' '0'写入byte数组中,而是把10000L在内存中的总共8个字节的二进制代码写入byte数组中
    31         
    32         dos.flush();
    33         byte[] buf = baos.toByteArray();  //DataOutputStream 流中并没有toByteArray()方法,但是ByteArrayOutputStream 流中却有toByteArray()方法, 所以不可以把baos 改为dos,否则编译时会出错! ByteArrayOutputStream流中toByteArray()方法的含义,摘自API“创建一个新分配的 byte 数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中”
    34 
    35         //利用ByteArrayInputStream 和 DataInputStream 可以从byte数组中得到原long类型的数值10000L
    36         ByteArrayInputStream bais = new ByteArrayInputStream(buf);
    37         DataInputStream dis = new DataInputStream(bais);
    38         long l = dis.readLong();
    39 
    40         System.out.println("l = " + l);
    41         dos.close();
    42     }
    43 }
    44 /*
    45     在JDK 1.6中的运行结果是:
    46 ----------------
    47 l = 9876543210
    48 ----------------
    49 */
    TestByteArrayOutputStream1
     1 /*
     2     功能:
     3         将long类型数据写入byte数组,然后在从byte数组中把该数据读出来
     4 */
     5 
     6 import java.io.*;
     7 
     8 public class TestByteArrayOutputStream2
     9 {
    10     public static void main(String[] args) throws Exception
    11     {
    12         long n = 1234567;
    13         ByteArrayOutputStream baos = new ByteArrayOutputStream();
    14         DataOutputStream dos = new DataOutputStream(baos);
    15         dos.writeLong(n);
    16         
    17         byte[] buf = baos.toByteArray();
    18         ByteArrayInputStream bis = new ByteArrayInputStream(buf);
    19         DataInputStream dis = new DataInputStream(bis);
    20         long n2 = dis.readLong();
    21         System.out.println("n2 = " + n2);
    22         
    23         dos.close(); 
    24         dis.close();
    25     }
    26 }
    TestByteArrayOutputStream2

     

    转换流:OutputStreamWriter InputStreamReader

    OutputStreamWriter 流是把OutputStream流 转化成Writer流的流

    InputStreamReader 流是把InputStream流转化为Reader

    OutputStreamWriter 和 InputStreamReader都是包裹流

    实例:如何将键盘输入的字符组成字符串直接赋给String对象。

     1 /*
     2     如何将键盘输入的字符组成字符串直接赋给String 对象
     3     
     4     预备知识:
     5 --------------------------------
     6 Reader FileReader InputStream FileInputStream BufferedInputStream 
     7 流中都没有 readLine 方法
     8     DataInputStream 流中有 readLine方法,但已经 被标记为过时
     9     BufferedReader 流中有readLine方法,并且该方法是可以正确被使用的
    10 --------------------------------
    11 */
    12 
    13 import java.io.*;
    14 
    15 public class TestStringInput
    16 {
    17     public static void main(String[] args) 
    18     {
    19         String str = null;
    20         BufferedReader br = new BufferedReader (   //21行
    21                     new InputStreamReader(System.in)
    22                 ); //23行  查API:从21行到23行的代码是不会抛出任何异常的
    23                 
    24         try
    25         {
    26             str = br.readLine(); //会抛出IOException异常
    27         }
    28         catch (IOException e)
    29         {
    30             e.printStackTrace();
    31             System.exit(-1);
    32         }    
    33         
    34         System.out.println("str = " + str);        
    35         try
    36         {
    37             br.close(); //会抛出IOException异常
    38         }
    39         catch (IOException e)
    40         {
    41             e.printStackTrace();
    42             System.exit(-1);
    43         }        
    44     }
    45 }
    46 /*
    47     在JDK 1.6中的运行结果是:
    48 --------------------------------
    49 sadd行政村123Asd?asd撒旦
    50 str = sadd行政村123Asd?asd撒旦
    51 --------------------------------
    52 */
    TestStringInput

    readLine()与回车符的问题:

    Print流  PrintWriter PrintStream

    Print 流只有输出,没有输入

    分类:

    PrintWriter输入字符

    PrintStream输出字符

    PrintWriter在OutputStream基础之上提供了增强的功能,既可以方便地输出各种类型数据(而不仅限于byte型)的格式化表示形式。

    PrintStream重载了print和println方法,用于各种不同类型数据的格式化输出。

    格式化输出是指将一个数据用其字符串格式输出。

    DataOutputStream 中的 WriteXXX(data)方法是把data在内存中的二进制数据写入文件

    PrintStream 中的println(data)是该数据格式化后的字符串写入文件

     1 /*
     2     DataOutputStream 中的 writeXXX(data)方法
     3  4     PrintStream 中的 println(data)的区别
     5     
     6     总结:
     7         DataOutputStream 中的 writeXXX(data)方法是把data在内存中的二进制数据写入文件
     8         PrintStream 中的 println(data)写出的是该数据的格式化后的字符串        
     9 */
    10 
    11 import java.io.*;
    12 
    13 public class TestPrintStream_1
    14 {
    15     public static void main(String[] args) throws Exception 
    16     {
    17         DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:/share/kk.txt"));
    18         dos.writeLong(12345);  //实际写入文件的是00 00 00 00 00 00 30 39
    19         dos.close();
    20         System.out.printf("%#X
    ", 12345);
    21         
    22         PrintStream ps = new PrintStream(new FileOutputStream("d:/share/kk2.txt"), true);
    23         ps.println(12345);  //实际写入文件的是'1' '2' '3' '4' '5'
    24         ps.close();
    25     }
    26 }
    TestPrintStream_1

    PrintWriter 提供了PrintStream的所有打印方法, 其方法也从不抛出IOException。

    与PrintStream的区别:

    标准输入输出的重定向:

    实例:编程实现将键盘输入的数据输入A文件中,如果输入有误,则把出错信息输出到B文件

     1 import java.io.*;
     2 
     3 public class TestSetSystemOut {
     4     public static void main(String[] args) {
     5         PrintStream ps_out = null;
     6 
     7         try {
     8             ps_out = new PrintStream(new FileOutputStream("d:/share/ww.txt"));
     9             System.setOut(ps_out); // 将System.out的值重新设置为ps_out,即System.out不在关联到显示器,而是关联到"d:/share/ww.txt"文件
    10             System.out.println(12); // 这实际上是把12输出到了System.out所关联的d:/share/ww.txt中
    11             System.out.println(55.5); // 同上
    12         } catch (Exception e) {
    13             e.printStackTrace();
    14         } finally {
    15             try {
    16                 ps_out.close();
    17             } catch (Exception e) {
    18                 e.printStackTrace();
    19             }
    20 
    21         }
    22     }
    23 }
    TestSetSystemOut
     1 /*
     2     功能: 将键盘输入的数据输入A文件中,如果输入有误,
     3            则把出错信息输出到B文件中
     4            
     5            标准输入输出流的重定向    
     6 */
     7 
     8 import java.io.*;
     9 import java.util.*;
    10 
    11 public class TestSetOutErr {
    12     public static void main(String[] args) {
    13         PrintStream psOut = null;
    14         PrintStream psError = null;
    15         Scanner sc = null;
    16 
    17         try {
    18             psOut = new PrintStream("d:/Out.txt");
    19             psError = new PrintStream("d:/error.txt");
    20             sc = new Scanner(System.in);
    21             int num;
    22             System.setOut(psOut);
    23             System.setErr(psError);
    24 
    25             while (true) {
    26                 num = sc.nextInt();
    27                 System.out.println(num);
    28             }
    29         } catch (Exception e) {
    30             System.err.println("出错的信息是:"); // 不可以写成System.out.println("出错的信息是:");
    31             e.printStackTrace(); // e.printStackTrace(); 默认是输出到System.err所关联的设备中
    32         }
    33     }
    34 }
    TestSetOutErr
    对象的序列化 ObjectOutputStream ObjectInputStream
    所谓序列化是指:把一个Object对象直接转化为字节流,然后把这个字节流直接写入本地硬盘或网络中
    序列化流(ObjectOutputStream)----writeObject
    反序列化流(ObjectInputStream)---readObject
    如果想把某个对象序列化,则必须实现Serializable接口
    transient关键字用用它修饰变量后该变量不会进行jvm默认的序列化
    当我们要把一个对象在网络上传输转化成字节序列,我们有些变量没必要使用,放在网络上传输会浪费资源,这个时候我们就会用transient关键字
    transient修饰的属性我们可以自己完成序列化
    transient关键字在有些情况下可以提高性能

    实例:

     1 import java.io.*;
     2 
     3 public class TestObjectIO
     4 {
     5     public static void main(String[] args)
     6     {
     7         ObjectOutputStream oos = null;
     8         ObjectInputStream ois = null;
     9         Student ss = new Student("zhansan", 1000, 88.8f);  //注意88.8f不能改为88.8 
    10         Student ss2 = null;    
    11                 
    12         try
    13         {
    14             FileOutputStream fos = new FileOutputStream("d:/share/java/ObjectOut.txt");
    15             oos = new ObjectOutputStream(fos);
    16             oos.writeObject(ss);
    17             
    18             ois = new ObjectInputStream(new FileInputStream("d:/share/java/ObjectOut.txt"));    
    19             ss2 = (Student)ois.readObject();  //(Student)不能省   ois.readObject();如果ois中的某个成员是transient,则该成员是不会被读取的,因为该成员不会被保存,何来读取之说?!
    20             
    21             System.out.println("ss2.sname = " + ss2.sname);
    22             System.out.println("ss2.sid = " + ss2.sid);
    23             System.out.println("ss2.sscore = " + ss2.sscore);
    24         }
    25         catch (FileNotFoundException e)
    26         {
    27             System.out.println("文件没有找到!");
    28             System.exit(-1);
    29         }
    30         catch (Exception e)
    31         {
    32             e.printStackTrace();
    33             System.exit(-1);
    34         }
    35         finally
    36         {
    37             try
    38             {
    39                 oos.close();
    40                 ois.close();
    41             }
    42             catch (Exception e)
    43             {
    44                 e.printStackTrace();
    45                 System.exit(-1);
    46             }
    47         }        
    48     }
    49 }
    50 
    51 class Student implements Serializable  //如果将implements Serializable 注释掉,则程序编译时就会报错
    52 {
    53     public String sname = null;
    54     public int sid = 0;
    55     transient public float sscore = 0; //表示sscore成员不能被序列化,所谓不能被序列化就是指:“该成员调用ObjectOutputStream 的writeOnbject()时不会被保存,调用ObjectInputStream的readObject()方法时不会被读取”
    56     
    57     public Student(String name, int id, float score)
    58     {
    59         this.sname = name;
    60         this.sid = id;
    61         this.sscore =  score;
    62     }
    63 }
    TestObjectIO
     
    分析ArrayList源码中序列化和反序列化的问题
    ArrayList的底层虽然是一个数组,但是这个数组不一定放满,没有放满的数组元素是不需要进行序列化的,我们必须自己完成序列化,把有效元素一个一个自己完成序列化 ,反序列化也一样,所以ArrayList源码中的序列化和反序列化的作用就是把ArrayList中的有效元素进行序列化 无效元素不进行序列化,可以提高性能。
    对ArrayList的源码有个初步的了解,能够进行序列化的优化问题
     
    序列化中 子类和父类构造函数的调用问题
    当一个子类的父类实现了序列化接口,子类可以直接进行序列化 ,子类序列化时会递归调用父类的构造方法。
    对子类对象进行反序列化操作时,如果其父类没有实现序列化接口,那么其父类的构造方法会被调用
  • 相关阅读:
    Integer和Integer常量池
    Spring中常用的23中设计模式
    GitHub 简单教程
    IDEA 中用好 Lombok,撸码效率至少提升5倍!
    Intellij IDEA中Mybatis Mapper自动注入警告的6种解决方案
    ROS常用命令和VIM常用命令
    ROS运行
    VINS-Mono运行
    环境配置相关
    C89标准和C99标准C11标准的区别
  • 原文地址:https://www.cnblogs.com/Wonderful-life217/p/8443934.html
Copyright © 2020-2023  润新知