文件传输基础——JavaIO流

字节流:

package com.lb;

public class IOUtil {
    //文件的遍历
    public static void listDirectory(File dir) throws IOException{
        if(!dir.exists()){
            throw new IOException("文件不存在!");
        }
        if(!dir.isDirectory()){
            throw new IOException("不是文件!");
        }
//      String[] dirs = dir.list();//获得String类型的文件名数组
//      for (String string : dirs) {
//          System.out.println(string);// 新建文件夹
//      }
        File[] dirs=dir.listFiles();
        if(dirs!=null && dirs.length>0){
            for (File file : dirs) {
                if(file.isDirectory()){
                    listDirectory(file);// 递归(遍历所有文件)
                }else{
                    System.out.println(file);// E:\LB\新建文件夹
                }
            }
        }
    }

    //单字节读取(不适合大文件)
    public static void printHex(String fileName) throws IOException{
        FileInputStream fis=new FileInputStream(fileName);
        int i=1;
        int b;
        while((b=fis.read()) != -1){
            if(b <= 0xf){
                System.out.print("0");
            }
            System.out.print(Integer.toHexString(b)+"  ");
            if(i++%10 ==0){
                System.out.println();
            }
        }
        fis.close();
    }

    //批量读取(常用、最快)
    public static void printHexByByteArray(String fileName)throws IOException{
        FileInputStream fis=new FileInputStream(fileName);
        byte[] buf=new byte[20*1024];
        //从fis中批量读取字节,放入到buf数组中
        //从0开始,最多放buf.length
        //返回的是读到的字节的个数
        int bytes=fis.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
        int j=1;
        while((bytes=fis.read(buf, 0, buf.length))!=-1){
            for(int i=0;i<bytes;i++){
                System.out.print(Integer.toHexString(buf[i] & 0xff)+" ");
                if(j++%10 == 0){
                    System.out.println();
                }
            }
        }
        fis.close();
    }

    //写入文件
    public static void writeFile(String fileName)throws IOException{
        //如果文件不存在,创建文件;如果文件存在,删除后再创建文件
        //若参数为(fileName,true),若文件存在,直接在文件末尾添加 
        FileOutputStream out=new FileOutputStream(fileName);
        out.write('A');
        int a=888;
        out.write(a >>> 24);
        out.write(a >>> 16);
        out.write(a >>> 8);
        out.write(a);
        byte[] bytes="我曹".getBytes("gbk");
        out.write(bytes);
        IOUtil.printHex(fileName);
        out.close();
    }

    //复制文件
    public static void copyFile(File fromFile,File toFile)throws IOException{
        if(!fromFile.exists()){
            throw new IllegalArgumentException("文件不存在!");
        }
        if(!fromFile.isFile()){
            throw new IllegalArgumentException("不是文件!");
        }
        FileInputStream in=new FileInputStream(fromFile);
        FileOutputStream out=new FileOutputStream(toFile);
        byte[] buf=new byte[20*1024];
        int bytes;
        while((bytes=in.read(buf,0,buf.length))!=-1){
            out.write(buf,0,bytes);
            out.flush();
        }
        in.close();
        out.close();
    }

    //测试DataIOStream
    public static void testDataIOStream(String fileName) throws IOException{
        DataOutputStream out=new DataOutputStream(new FileOutputStream(fileName));
        out.writeInt(10);
        out.writeDouble(5.1);
        //utf-8编码形式写入
        out.writeUTF("哈哈");
        //utf-16be编码形式写入
        out.writeBytes("中国");
        DataInputStream in=new DataInputStream(new FileInputStream(fileName));
        System.out.println(in.readInt());
        System.out.println(in.readDouble());
        System.out.println(in.readUTF());

        in.close();
        out.close();
    }

    //测试BufferedIOStream
    public static void copyByBuffer(File fromFile,File toFile)throws IOException{
        if(!fromFile.exists()){
            throw new IllegalArgumentException("文件不存在!");
        }
        if(!fromFile.isFile()){
            throw new IllegalArgumentException("不是文件!");
        }
        BufferedInputStream in =new BufferedInputStream(new FileInputStream(fromFile));
        BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(toFile));
        //如果不加缓冲,直接读写文件,会变慢
        int bytes;
        while((bytes=in.read())!=-1){
            out.write(bytes);
            out.flush();
        }
        in.close();
        out.close();
    }
}
package com.lb;

import java.io.File;
import java.io.IOException;

public class IOUtilTest {

    /**
     * gbk:中文2,英文1   utf-8:中文3,英文1   utf-16be:中文2,英文2
     * IO流
     * 
     * 1.字节流
     * 1)InputStream、OutputStream
     *    InputStream抽象了应用程序读取数据的方式
     *    OutputStream抽象了应用程序写出数据的方式
     * 2)EOF = End 读到-1就结束
     * 3)输入流基本方法:
     *    int b=in.read();//读取一个字节,无符号填充到int低8位,-1是EOF
     *    in.read(byte[] buf)
     *    in.read(byte[] buf,int start,int size)
     * 4)输出流基本方法:
     *    out.write(int b)//写出一个byte到流,b的低8位
     *    out.write(byte[] buf)//将buf字节数组都写入到流
     *    out.write(byte[] buf,int start,int size)
     * 5)FileInputStream继承InputStream--->具体实现了在文件上读取数据
     * 6)FileOutputStream继承OutputStream--->实现了向文件中写出byte数据的方法
     * 7)DataOutputStream、DataInputStream
     *    对“流”的扩展,更方便的读取、写入数据类型
     * 8)BufferedInputStream、BufferedOutputStream
     *    为IO提供了带缓冲区的操作,写入或读取操作时,会加上缓冲,提高了IO性能
     *    
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        //File类只用于表示文件、目录的信息(名称、大小),不能用于文件的访问
        File file=new File("E:\\LB");
        if(!file.exists())
            file.mkdir();//创建文件夹        mkdirs:创建多级目录
        else
            file.delete();
        System.out.println(file.isDirectory()+"+"+file.isFile());//是不是目录,是不是文件
        File file2=new File("E:\\LB.txt");
        if(!file2.exists())
            file2.createNewFile();//创建文件
        System.out.println(file);//E:\LB
        System.out.println(file.getName());//LB
        System.out.println(file2.getName());//LB.txt
        System.out.println(file.getParentFile().getAbsolutePath());//E:\

//      long start=System.currentTimeMillis();
//      IOUtil.printHexByByteArray("E:\\LB\\1.exe");//高效
//      IOUtil.printHex("E:\\LB\\1.zip");//很慢
//      long end=System.currentTimeMillis();
//      System.out.println();
//      System.out.println(end-start);

//      IOUtil.writeFile("E:\\LB\\195.txt");

//      IOUtil.copyFile(new File("E:\\LB\\1.exe"),new File("E:\\LB\\8888.exe"));

//      IOUtil.testDataIOStream("E:\\LB\\195.txt");

        long start=System.currentTimeMillis();
        IOUtil.copyByBuffer(new File("E:\\LB\\1.exe"),new File("E:\\LB\\8888.exe"));//2876
//      IOUtil.copyFile(new File("E:\\LB\\1.exe"),new File("E:\\LB\\8889.exe"));//400+
        long end=System.currentTimeMillis();
        System.out.println(end-start);

    }
}
package com.lb;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;

public class RandomAccessFileTest {

    /**
     * RandomAccessFile :对文件内容的访问,既可以读,也可以写
     * 支持随机访问文件,可以访问文件的任意位置
     * 1.java文件模型
     *      硬盘上的文件是byte byte byte存储的,是数据的集合
     * 2.打开文件
     *      两种模式(mode):rw(读写),r(只读)
     *      RandomAccessFile raf = new RandomAccessFile(file,"rw");
     *      文件指针:打开文件时指针在开头 pointer = 0;
     * 3.写方法
     *      raf.write(int)--->只写一个字节(后8位),同时指针指向下一个位置,准备下一次写入
     *      raf.writeInt(int)
     * 4.读方法
     *      int b = raf.read()--->读取一个字节
     * 5.文件写完之后一定要关闭
     * */
    public static void main(String[] args) throws IOException {

        File file =new File("E:\\LB\\44442.txt");
        if(!file.exists())
            file.createNewFile();
        RandomAccessFile raf=new RandomAccessFile(file, "rw");
        // 1.写入字节
        raf.write('A');//一次只写一个字节(后8位)
        System.out.println(raf.getFilePointer());//获取指针位置 1
        // 2.写入int
        int i=0x7fffffff;
//      raf.write(i >>> 24);//高8位
//      raf.write(i >>> 16);
//      raf.write(i >>> 8);
//      raf.write(i);
        raf.writeInt(i);//上面为其实现机制
        System.out.println(raf.getFilePointer());//5
        // 3.写入String
        String s="中";
        byte[] bytes=s.getBytes("gbk");
        raf.write(bytes);
        System.out.println(raf.getFilePointer());//7
        // 4.读文件
        raf.seek(0);//读文件时必须把指针移到头部
        byte[] buf=new byte[(int)raf.length()];//一次性读取,把文件内容都读到字节数组中
        raf.read(buf);
        //遍历1
        System.out.print(Arrays.toString(buf)+" ");//[65, 127, -1, -1, -1, -42, -48]
        //遍历2
        String s2=new String(buf,"gbk");
        System.out.println("\n"+s2);//A???中
        //遍历3
        for (byte b : buf) {
            System.out.print(Integer.toHexString(b & 0xff)+" ");//41 7f ff ff ff d6 d0 
        }
        raf.close();
    }
}

字符流:

package com.lb;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.management.BufferPoolMXBean;

public class CharStreamTest {

    /**
     * 字符流:
     * 1)编码问题
     * 2)认识文本和文本文件
     *    java中的文本(char)是16位无符号整数,是字符的Unicode编码(双字节编码)
     *    文件是byte byte byte的数据序列
     *    文本文件是文本(char)序列按照某种编码方案(utf-8,gbk)序列化为byte的存储结果
     * 3)字符流--->操作的是文本文件
     *    字符的处理,一次处理一个字符
     *    字符的底层仍然是基本的字节序列
     *    字符流的基本实现:
     *       InputStreamReader完成byte流转化为char流
     *       OutputStreamWriter提供char流转化为byte流
     *       均按照编码处理
     * 4)FileReader、FileWriter
     *    构造方便,但不能表示文本的编码格式
     * 5)BufferedReader、BufferedWriter
     *    一次读一行、写一行--->readLine()
     */

    public static void main(String[] args) throws IOException {
//      InputStreamReader isr=new InputStreamReader(new FileInputStream("E:\\LB\\8888.txt"),"gbk");
//      OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\LB\\9999.txt"),"gbk");
        /*FileReader isr=new FileReader("E:\\LB\\8888.txt");
        FileWriter osw=new FileWriter("E:\\LB\\9999.txt",true);//true:在文件中继续写
        int b;
        char[] buf=new char[8*1024];
        while((b=isr.read(buf, 0, buf.length))!=-1){
            osw.write(buf, 0, b);
            osw.flush();
            String s=new String(buf,0,b);
            System.out.print(s);
        }
        isr.close();
        osw.close();*/
        /**********************************************************************/
        BufferedReader br=new BufferedReader(new FileReader("E:\\LB\\9999.txt"));
        BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\LB\\8899.txt"));
//      PrintWriter pw=new PrintWriter("E:\\LB\\878.txt");
        String s;
        while((s=br.readLine())!=null){
            bw.write(s);
            bw.newLine();//单独写出换行操作
            bw.flush();
            System.out.println(s);
//          pw.println(s);
//          pw.flush();
        }
        br.close();
        bw.close();
//      pw.close();
    }
}

对象的序列、反序列化:

package com.lb;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

@SuppressWarnings("serial")
public class ObjectSerializableTest implements Serializable{
    /**
     * 对象的序列化,反序列化
     * 1)对象序列化,就是将Object转换成byte序列,反之为反序列化
     * 2)序列化流(ObjectOutputStream)--->writeObject
     *    反序列化流(ObjectInputStream)--->readObject
     * 3)序列化接口(Serializable)
     *    对象必须实现序列化接口,否则异常 
     * 4)transient关键字
     *    特定情况下能提高性能
     *    如:数组元素没放满,只需要对已经放入的元素进行序列化
     * 5)序列化中子父类构造函数的问题
     *    一个类实现了序列化接口,那么其子类都可以进行序列化
     *    对子类对象进行反序列化操作时,如果其父类没有实现序列化接口,那么其父类的构造函数会被调用
     */
    private String name;
    private transient int age;
    private String sex;//该元素不会进行jvm(虚拟机)默认的序列化,可以自己完成这个元素的序列化

    public ObjectSerializableTest(){

    }
    public ObjectSerializableTest(String name, int age, String sex) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "ObjectSerializableTest [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }
    //自己实现序列化和反序列化
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException{
        s.defaultWriteObject();//把jvm能默认序列化的序列化
        s.writeInt(age);//自己完成sex的序列化
    }
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException{
        s.defaultReadObject();
        this.age=s.readInt();//自己完成sex的反序列化
    }
    public static void main(String[] args) throws Exception {
        ObjectSerializableTest ost=new ObjectSerializableTest("张三",4,"男");
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("E:\\LB\\99999.txt"));
        oos.writeObject(ost);
        oos.flush();
        oos.close();

        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("E:\\LB\\99999.txt"));
        System.out.println((ObjectSerializableTest)ois.readObject());
        ois.close();

    }

}
点赞