文件传输基础----Java IO流

来源:互联网 发布:2017淘宝入门基础知识 编辑:程序博客网 时间:2024/06/05 05:47

编码问题

一个很著名的奇怪现象:当你在 windows 的记事本里新建一个文件,输入"联通"两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是几个乱码!呵呵,有人说这就是联通之所以拼不过移动的原因。
其实这是因为GB2312编码与UTF8编码产生了编码冲撞的原因。
GB系中“联通”的二进制编码为:11000001 10101010 11001101 10101000

注意到了吗?第一二个字节、第三四个字节的起始部分的都是"110"和"10",正好与UTF8规则里的两字节模板是一致的,于是再次打开记事本时,记事本就误认为这是一个UTF8编码的文件,让我们把第一个字节的110和第二个字节的10去掉,我们就得到了"00001 101010",再把各位对齐,补上前导的0,就得到了"0000 0000 0110 1010",不好意思,这是UNICODE的006A,也就是小写的字母"j",而之后的两字节用UTF8解码之后是0368,这个字符什么也不是。这就是只有"联通"两个字的文件没有办法在记事本里正常显示的原因。

而如果你在"联通"之后多输入几个字,其他的字的编码不见得又恰好是110和10开始的字节,这样再次打开时,记事本就不会坚持这是一个utf8编码的文件,而会用ANSI的方式解读之,这时乱码又不出现了。

package com.imooc.io;import java.io.UnsupportedEncodingException;/** * Created by N3verL4nd on 2017/3/8. */public class EncodeDemo {    public static void main(String[] args) throws UnsupportedEncodingException {        String str = "慕课ABC";        byte[] bytes = str.getBytes("GBK");        //gbk编码中文占用两个字节,英文占用1个字节        for (byte b : bytes) {            //把字节(转换成了int)以16进制的方式显示            System.out.print(Integer.toHexString(b & 0xff) + " ");        }        /**         * 当你的字节序列使用某种编码时,如果把字节序列转化为         * 字符串,也需要使用相同的编码方式,否则出现乱码         */        System.out.println(new String(bytes));//用项目默认的编码方式        System.out.println("\n" + new String(bytes, "UTF-8"));        System.out.println(new String(bytes, "GBK"));        bytes = str.getBytes("UTF-8");        //UTF-8编码中文占用三个字节,英文占用1个字节        for (byte b : bytes) {            System.out.print(Integer.toHexString(b & 0xff) + " ");        }        System.out.println("\n" + new String(bytes));        //java是双字节编码 UTF-16BE        bytes = str.getBytes("UTF-16BE");        //utf-16be 中文占用2个字节,英文占用两个字节        for (byte b : bytes) {            System.out.print(Integer.toHexString(b & 0xff) + " ");        }        System.out.println("\n" + new String(bytes, "UTF-16BE"));        /**         * 文本文件保存的字节序列         * 可以死任意编码的字节序列         * 在中文机器上创建的文本文件默认是ANSI         */    }}

c4 bd bf ce 41 42 43 
Ľ��ABC
Ľ��ABC
慕课ABC
e6 85 95 e8 af be 41 42 43 
慕课ABC
61 55 8b fe 0 41 0 42 0 43 
慕课ABC

参考:

http://www.iteedu.com/topic/charset/utf8.php

http://oznyang.iteye.com/blog/30692

https://www.zhihu.com/question/25367290

File类的使用

作用:用于表示文件(目录),只能表示文件(目录)的信息,不能用于文件的访问。

package com.imooc.io;import java.io.File;import java.io.IOException;/** * Created by N3verL4nd on 2017/3/9. */public class FileDemo {    public static void main(String[] args) {        File file = new File("D:/Java/IdeaProjects/JavaProj/JTest/src/com/imooc/io/doc");        //System.out.println(file.isDirectory());        if (!file.exists()) {            file.mkdir();            System.out.println("路径 " + file.getAbsolutePath() + " 被创建!");        } else {            file.delete();            System.out.println("路径 " + file.getAbsolutePath() + " 被删除!");        }        file = new File("D:/Java/IdeaProjects/JavaProj/JTest/src/com/imooc/io/doc.txt");        //file = new File("D:/Java/IdeaProjects/JavaProj/JTest/src/com/imooc/io/", "doc.txt");        //System.out.println(file.isFile());        if (!file.exists()) {            try {                //创建文件                file.createNewFile();                System.out.println("文件 " + file.getName() + " 被创建!");            } catch (IOException e) {                e.printStackTrace();            }        } else {            //删除文件            file.delete();            System.out.println("文件 " + file.getName() + " 被删除!");        }    }}
package com.imooc.io;import java.io.File;/** * Created by N3verL4nd on 2017/3/9. * 列出File类的一些常用操作,比如过滤、遍历等 */public class FileUtils {    /**     * 列出指定目录下(包括其子目录)的所有文件     * @param file     */    public static void listDirectory(File file) throws IllegalArgumentException {        if (!file.exists()) {            throw new IllegalArgumentException("目录 " + file + " 不存在!");        }        if (!file.isDirectory()) {            throw new IllegalArgumentException(file + " 不是目录!");        }        /*//返回字符串数组,包括该目录下的目录名和文件名,不包括子目录        for (String patName : file.list()) {            System.out.println(file + "\\" + patName);        }*/        for (File f : file.listFiles()) {            if (f.isFile()) {                System.out.println("[文件]:" + f);            } else if (f.isDirectory()) {                System.out.println("[目录]:" + f.getAbsolutePath());                listDirectory(f);            }        }    }}

RandomAccessFile的使用

java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,即可以访问问价你的任意位置。
1、Java文件模型
在硬盘上的文件是byte byte byte存储的,是数据的集合
2、打开文件
"rw"(读写) "r"(读)
RandomAccessFile raf = new RandomAccessFile(file, "rw");

其封装由文件指针

3、写方法

raf.write(int)-->只写1个字节(后8位),同时文件指针指向下一个位置

4、读方法

int b = raf.read() --->读一个字节

5、文件读写完成后一定要关闭

raf.close();

package com.imooc.io;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;import java.util.Arrays;/** * Created by N3verL4nd on 2017/3/9. */public class rafDemo {    public static void main(String[] args) throws IOException {        File file = new File("JTest/doc.txt");        if (!file.exists())            file.createNewFile();        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");        //指针的位置        System.out.println(randomAccessFile.getFilePointer());        randomAccessFile.write('A');//只写了1个字节 'A'-->65-->01000001        System.out.println(randomAccessFile.getFilePointer());        randomAccessFile.write('B');        System.out.println(randomAccessFile.getFilePointer());        int x = 0x7fffffff;        randomAccessFile.write(x >>> 24);//8        randomAccessFile.write(x >>> 16);        randomAccessFile.write(x >>> 8);        randomAccessFile.write(x);        System.out.println(randomAccessFile.getFilePointer());        //randomAccessFile.writeInt(x);        randomAccessFile.write("李广辉".getBytes());        System.out.println("文件长度:" + randomAccessFile.length());        //读文件,必须把指针移到头部        randomAccessFile.seek(0);        byte[] buf = new byte[(int) randomAccessFile.length()];        randomAccessFile.read(buf);        System.out.println(Arrays.toString(buf));        for (byte b : buf) {            System.out.print(Integer.toHexString(b & 0xff) + " ");        }        System.out.println();        System.out.println(new String(buf, "UTF-8"));        randomAccessFile.close();    }}

字节流的使用

InputStream:抽象了应用程序读取数据的方式

OutputStream:抽象了应用程序写入数据的方式

EOF end of file:读到-1就读到了结尾

输入流的基本方法:

int b = in.read();读取一个字节无符号填充到int低八位

in.read(byte[] buf);读取数据填充到字节数组buf

in.read(byte[] buf, int start, int size);读取数据填充到字节数组buf,从buf的start位置开始,存放size长度的数据。

输出流:

out.write(int b);写出1个byte到流,b的低八位

out.write(byte[] buf)将buf字节数组都写入到流

out.write(byte[] buf, int start, int size);

FileInputStream-->具体实现了在文件上的输入操作

package com.imooc.io;import java.io.FileInputStream;import java.io.IOException;/** * Created by N3verL4nd on 2017/3/10. */public class IOUtil {    /**     * 读取指定文件内容,按照16进制输出到控制台     * 并且每输出10byte换行     * @param fileName     */    public static void printHex(String fileName) throws IOException {        //把文件作为字节流进行读操作        FileInputStream in = new FileInputStream(fileName);        int b;        int i = 1;        while ((b = in.read()) != -1) {            i++;            if (b <= 0xf) {                //单位数前面补0                System.out.print("0");            }            System.out.print(Integer.toHexString(b) + " ");            if (i % 10 == 0) {                System.out.println();            }        }        in.close();    }    public static void printHexByByteArray(String fileName) throws IOException{        FileInputStream in = new FileInputStream(fileName);        byte[] buf = new byte[20 * 1024];        /**         * in中批量读取字节,放入buf这个字节数组中         * 从第0个位置开始做,最多放buf.length个字节         * 返回的是读到的字节的个数         */        /*int bytes = in.read(buf, 0, buf.length);        int j = 1;        for (int i = 0; i < bytes; i++) {            j++;            if (buf[i] <= 0xf) {                System.out.print("0");            }            System.out.print(Integer.toHexString(buf[i]) + " ");            if (j % 10 == 0) {                System.out.println();            }        }*/        int bytes;        while ((bytes = in.read(buf, 0, buf.length)) != -1) {            int j = 1;            for (int i = 0; i < bytes; i++) {                j++;                if (buf[i] <= 0xf) {                    System.out.print("0");                }                System.out.print(Integer.toHexString(buf[i] & 0xff) + " ");                if (j % 10 == 0) {                    System.out.println();                }            }        }    }}
FileOutputStream实现了向文件写出byte数据的方法
package com.imooc.io;import java.io.FileOutputStream;import java.io.IOException;/** * Created by N3verL4nd on 2017/3/10. */public class FileOutDemo {    public static void main(String[] args) throws IOException {        //如果该文件不存在,则直接创建,如果不存在,则删除后创建        FileOutputStream out = new FileOutputStream("D:\\Java\\IdeaProjects\\JavaProj\\JTest\\doc.txt");        //out.write('A');        //out.write('B');        int x = 3389;        out.write(x >>> 24);        out.write(x >>> 16);        out.write(x >>> 8);        out.write(x);        //out.write("中国".getBytes());        IOUtil.printHex("D:\\Java\\IdeaProjects\\JavaProj\\JTest\\doc.txt");        out.close();    }}

package com.imooc.io;import java.io.*;/** * Created by N3verL4nd on 2017/3/10. */public class FileCopy {    public static void Copy(File src, File dst) throws IOException {        if (!src.exists()) {            throw new IllegalArgumentException(src + "不存在!");        }        if (!src.isFile()) {            throw new IllegalArgumentException(src + "不是文件!");        }        FileInputStream in = new FileInputStream(src);        FileOutputStream out = new FileOutputStream(dst);        int len;        byte[] buf = new byte[1024];        while ((len = in.read(buf, 0, 1024)) != -1) {            out.write(buf, 0, len);        }        in.close();        out.close();    }    public static void main(String[] args) {        try {            Copy(new File("D:\\N3verL4nd\\Desktop\\Pro.txt"), new File("D:\\Java\\IdeaProjects\\JavaProj\\JTest\\doc.txt"));        } catch (IOException e) {            e.printStackTrace();        }    }}

DataOutputStream/DataInputStream

对流功能的扩展,可以更加方便的读取int,long,字符等类型的数据

DataOutputStream

writeInt(),writeDouble(),writeUTF()

package com.imooc.io;import java.io.*;/** * Created by N3verL4nd on 2017/3/11. */public class DosDemo {    public static void main(String[] args) throws IOException {        String filename = "D:\\Java\\IdeaProjects\\JavaProj\\JTest\\doc.txt";        DataOutputStream out = new DataOutputStream(new FileOutputStream(filename));        out.writeInt(100);        out.writeDouble(1.1);        //采用UTF-8编码写出        out.writeUTF("你好");        //采用UTF-16BE编码写出        out.writeChars("中国");        out.close();//        IOUtil.printHex(filename);        DataInputStream in = new DataInputStream(new FileInputStream(filename));        System.out.println(in.readInt());        System.out.println(in.readDouble());        System.out.println(in.readUTF());        System.out.println(in.readChar());        System.out.println(in.readChar());        in.close();    }}
BufferedInputStream/BufferedOutputStream

这两个流为IO提供了带缓冲区的操作,一般打开文件进行读写都会加上缓冲区,从而提高IO性能。

字符流的使用

文本和文本文件:

java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)

文件是byte byte byte的数据序列

文本文件是文本序列按照某种编码方案(UTF-8/UTF-16BE,GBK)序列化为byte的存储文件

字符流(Reader和Writer)

字符的处理,一次处理一个字符

字符的底层仍然是基本的字节序列

字符流的基本实现

InputStreamReader 完成byte流解析为char流,按照编码解析

OutputStreamWriter 提供char流到byte流,按照编码处理

package com.imooc.io;import java.io.*;/** * Created by N3verL4nd on 2017/3/12. */public class OSWDemo {    public static void main(String[] args) {        String fileName = "D:\\N3verL4nd\\Desktop\\Pro.txt";        InputStreamReader isr = null;//默认项目编码        try {            isr = new InputStreamReader(new FileInputStream(fileName), "UTF-8");        } catch (UnsupportedEncodingException | FileNotFoundException e) {            e.printStackTrace();        }        /*try {            int c;            while ((c = isr.read()) != -1) {                System.out.print((char)c);            }            isr.close();        } catch (IOException e) {            e.printStackTrace();        }*/        char[] buf = new char[1024];        int len;        try {            //批量读取,放入buffer这个字符数组,从第0个位置开始,最多放1024个            //返回读取字符的个数            while ((len = isr.read(buf, 0, 1024)) != -1) {                System.out.print(new String(buf, 0, len));            }            isr.close();        } catch (IOException e) {            e.printStackTrace();        }    }}
FileReder/FileWriter继承自InputStreamReader/OutputStreamWriter,使其对文件读写更加方便。
package com.imooc.io;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;/** * Created by N3verL4nd on 2017/3/12. */public class FRFW {    public static void main(String[] args) throws IOException {        FileReader reader = new FileReader("D:\\N3verL4nd\\Desktop\\Pro.txt");        int c;        while ((c = reader.read()) != -1) {            System.out.println(c);        }        reader.close();    }} 
字符流的过滤器

BufferedReader -->readLine 一次读一行
BufferedWriter -->writeLine一次写一行

package com.imooc.io;import java.io.*;/** * Created by N3verL4nd on 2017/3/10. */public class FileCopy {    public static void Copy(File src, File dst) throws IOException {        if (!src.exists()) {            throw new IllegalArgumentException(src + "不存在!");        }        if (!src.isFile()) {            throw new IllegalArgumentException(src + "不是文件!");        }        FileInputStream in = new FileInputStream(src);        FileOutputStream out = new FileOutputStream(dst);        int len;        byte[] buf = new byte[1024];        while ((len = in.read(buf, 0, 1024)) != -1) {            out.write(buf, 0, len);        }        in.close();        out.close();    }    public static void CopyFileByBuffer(File src, File dst) throws IOException {        if (!src.exists()) {            throw new IllegalArgumentException(src + "不存在!");        }        if (!src.isFile()) {            throw new IllegalArgumentException(src + "不是文件!");        }        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dst));        int len;        byte[] buf = new byte[1024];        while ((len = in.read(buf, 0, 1024)) != -1) {            out.write(buf, 0, len);//            out.flush();//刷新缓冲区        }        in.close();        out.close();    }    public static void main(String[] args) {        try {            long start = System.currentTimeMillis();            CopyFileByBuffer(new File("F:\\H4ck\\bjut\\db.html"), new File("D:\\Java\\IdeaProjects\\JavaProj\\JTest\\doc.txt"));            //Copy(new File("F:\\H4ck\\bjut\\db.html"), new File("D:\\Java\\IdeaProjects\\JavaProj\\JTest\\doc.txt"));            long end = System.currentTimeMillis();            System.out.println(end - start);        } catch (IOException e) {            e.printStackTrace();        }    }}

package com.imooc.io;import java.io.*;/** * Created by N3verL4nd on 2017/3/12. */public class BRBW {    public static void main(String[] args) throws IOException {        BufferedReader reader = new BufferedReader(                new InputStreamReader(                        new FileInputStream("D:\\N3verL4nd\\Desktop\\Pro.txt")                ));        while (reader.ready()) {            System.out.println(reader.readLine());        }        reader.close();    }}

对象的序列化和反序列化

对象的序列化就是将Objext转换成byte序列,反之叫做反序列化。
序列化流:ObjextOutputStream--->writeObject
反序列化:ObjectInputStream--->readObject
序列化接口(Serializable)
对象必须实现序列化接口,才能进行序列化,否则将出现异常。
这个接口没有任何方法,只是一个标准。
package com.imooc.io;import java.io.Serializable;/** * Created by N3verL4nd on 2017/3/12. */public class Student implements Serializable{    private String stuNO;    private String name;    private int age;    public Student() {    }    public Student(String stuNO, String name, int age) {        this.stuNO = stuNO;        this.name = name;        this.age = age;    }    public String getStuNO() {        return stuNO;    }    public void setStuNO(String stuNO) {        this.stuNO = stuNO;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "Student{" +                "stuNO='" + stuNO + '\'' +                ", name='" + name + '\'' +                ", age=" + age +                '}';    }}

package com.imooc.io;import java.io.*;/** * Created by N3verL4nd on 2017/3/12. */public class ObjectSerializable {    public static void main(String[] args) {        String fileName = "D:\\Java\\IdeaProjects\\JavaProj\\JTest\\src\\com\\imooc\\io\\doc\\data.dat";        Student student = new Student("10010", "lgh", 24);        try {            //对象的序列化            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));            //student对象保存起来            out.writeObject(student);            out.close();            ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));            Student stu = (Student) in.readObject();            System.out.println(stu);        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}
private transient int age;//该元素不会进行虚拟机默认的序列化工作

该元素不会进行虚拟机默认的序列化工作,也可以自己完成这个元素的序列化
我们可以参考ArrayList的相关操作:
private void readObject(java.io.ObjectInputStream s)    throws java.io.IOException, ClassNotFoundException {    elementData = EMPTY_ELEMENTDATA;    // Read in size, and any hidden stuff    s.defaultReadObject();    // Read in capacity    s.readInt(); // ignored    if (size > 0) {        // be like clone(), allocate array based upon size not capacity        ensureCapacityInternal(size);        Object[] a = elementData;        // Read in all elements in the proper order.        for (int i=0; i<size; i++) {            a[i] = s.readObject();        }    }}
private void writeObject(java.io.ObjectOutputStream s)    throws java.io.IOException{    // Write out element count, and any hidden stuff    int expectedModCount = modCount;    s.defaultWriteObject();    // Write out size as capacity for behavioural compatibility with clone()    s.writeInt(size);    // Write out all elements in the proper order.    for (int i=0; i<size; i++) {        s.writeObject(elementData[i]);    }    if (modCount != expectedModCount) {        throw new ConcurrentModificationException();    }}
package com.imooc.io;import java.io.IOException;import java.io.ObjectOutputStream;import java.io.Serializable;import java.util.ArrayList;/** * Created by N3verL4nd on 2017/3/12. */public class Student implements Serializable{    private String stuNO;    private String name;    private transient int age;//该元素不会进行虚拟机默认的序列化工作    public Student() {    }    public Student(String stuNO, String name, int age) {        this.stuNO = stuNO;        this.name = name;        this.age = age;    }    public String getStuNO() {        return stuNO;    }    public void setStuNO(String stuNO) {        this.stuNO = stuNO;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "Student{" +                "stuNO='" + stuNO + '\'' +                ", name='" + name + '\'' +                ", age=" + age +                '}';    }    private void writeObject(java.io.ObjectOutputStream s)            throws java.io.IOException{        //按照jvm默认序列化的元素进行序列化操作        s.defaultWriteObject();        //自己完成age的序列化操作        s.writeInt(age);    }    private void readObject(java.io.ObjectInputStream s)            throws java.io.IOException, ClassNotFoundException {        s.defaultReadObject();        this.age = s.readInt();    }}

transient Object[] elementData; // non-private to simplify nested class access
ArrayList所做的是数组有效数据元素的序列化操作

一个类实现了序列化接口,那么其子类都可以进行序列化操作
序列化中子类和父类构造函数的调用问题:
对子类对象进行反序列化操作时,
如果其父类没有实现序列化接口,那么其父类的构造函数会被调用。
package com.imooc.io;import java.io.*;/** * Created by N3verL4nd on 2017/3/12. */class A{    public A() {        System.out.println("A");    }}class B extends A implements Serializable{    public B() {        System.out.println("B");    }}class C extends B{    public C() {        System.out.println("C");    }}public class Demo {    public static void main(String[] args) {        C c = new C();        try {            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.dat"));            out.writeObject(c);            out.close();            System.out.println("---------------------");            ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.dat"));            in.readObject();        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}


0 0