文件传输基础——Java IO流

来源:互联网 发布:curl json 编辑:程序博客网 时间:2024/06/05 22:10

    • 文件的编码
      • 1 文件的编码
    • File 类的使用
      • 1 File 类常用 API 介绍
      • 2 遍历目录
    • RandomAccessFile类的使用
      • 1 RandomAccessFile基本操作
    • 字节流
      • 1 字节流之文件输入流FileInputStream-1
      • 2 字节流之文件输入流FileInputStream-2
      • 3 字节流之文件输出流FileOutputStream
      • 4 字节流之数据输入输出流
      • 5 字节缓冲流
    • 字符流
      • 1 字节字符转换流

1 文件的编码

1.1 文件的编码

这里写图片描述

public static void main(String[] args) {    // TODO Auto-generated method stub    String s = "慕课ABC";    /**     * 转换成字节序列利用的是项目默认的编码,     * eclipse查看项目默认编码的方式:点击项目->右击Properties->Resource->Text file encoding     * 项目编码也可以显示的指定:byte[] bytes = s.getBytes("gbk");      */    byte[] bytes1 = s.getBytes();     for(byte b:bytes1) {        // 把字节转换为int,以16进制的方式显示        System.out.print(Integer.toHexString(b & 0xff) + " ");    }    System.out.println();    try {        byte[] bytes2 = s.getBytes("gbk");        /**         * gbk编码中文占2个字节,英文占1个字节         */        for(byte b:bytes2) {            System.out.print(Integer.toHexString(b & 0xff) + " ");        }    } catch (UnsupportedEncodingException e) {        // TODO Auto-generated catch block        e.printStackTrace();    }    System.out.println();    try {        byte[] bytes3 = s.getBytes("utf-8");        /**         * 在utf-8编码中,中文占用3个字节,英文占用1个字节         */        for(byte b:bytes3) {            System.out.print(Integer.toHexString(b & 0xff)+" ");        }    } catch (UnsupportedEncodingException e) {        // TODO Auto-generated catch block        e.printStackTrace();    }    System.out.println();    byte[] bytes4 = null;    try {        /**         * 在utf-16be中,中文和英文都占用2个字节         */        bytes4 = s.getBytes("utf-16be");        for(byte b:bytes4) {            System.out.print(Integer.toHexString(b & 0xff)+" ");        }    } catch (UnsupportedEncodingException e) {        // TODO Auto-generated catch block        e.printStackTrace();    }    System.out.println();    /**     * 字节序列转化为字符串时,当你的字节序列的编码方式与项目默认编码方式不同时,     * 这个时候需要手动添加编码方式进行转换,     * 否则会出现乱码     *      */    String str1 = new String(bytes4);    System.out.println(str1);    try {        String str2 = new String(bytes4,"utf-16be");        System.out.println(str2);    } catch (UnsupportedEncodingException e) {        // TODO Auto-generated catch block        e.printStackTrace();    }    /**     * eclipse中什么编码的项目只认识什么编码的文件,     * 将一个项目的文件拷贝到另一个编码方式不同的项目中,就会出现乱码,     * 这就是直接拷贝别人项目文件出现乱码的原因     */     /**     * 文本文件 就是字节序列     * 可以是任意编码的字节序列     * 如果我们在中文机器上直接创建文本文件,那么该文本文件只认识ansi编码     */}

2 File 类的使用

2.1 File 类常用 API 介绍

java.io.File 类用于表示文件(目录)
File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问

public static void main(String[] args) {    // TODO Auto-generated method stub    /**     * eclipse中用 Alt+/ 来查看File的构造函数,     * 文件分割符可以用 \\ 或者 / 或者  File.separator,     * File.separator不论win系统还是linux系统,都表示分割符     */    File file = new File("D:\\javaio");     System.out.println(file.exists()); // 判断文件是否存在    if(!file.exists()) {         file.mkdir(); // 创建一级目录        file.mkdirs(); // 如果文件不存在,创建多级目录    }else {        file.delete(); // 如果文件存在,删除目录    }    /**     * 判断是否是一个目录 ,     * 如果是目录返回true,如果不是目录或者不存在返回false     */    System.out.println(file.isDirectory());    // 判断是否是一个文件    System.out.println(file.isFile());    /**     * 创建文件     */    File file2 = new File("d:\\javaio\\日记1.txt");    File file3 = new File("d:\\javaio","日记2.txt");    if(!file2.exists()) {        try {            file2.createNewFile(); // 文件不存在,创建这个文件        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }else {        file2.delete(); // 文件存在删除文件    }    // 常用的File对象的API    System.out.println(file); // 打印file.toString()的内容    System.out.println(file.getAbsolutePath()); // 打印路径    System.out.println(file.getName()); // 打印目录名    System.out.println(file2.getName()); // 打印文件名    System.out.println(file.getParent()); // 返回父目录路径    System.out.println(file2.getParent()); // 返回父目录路径    System.out.println(file.getParentFile().getAbsolutePath()); // 返回父目录路径}

2.2 遍历目录

package com.amoscxy;import java.io.File;import java.io.IOException;/** * 列出File的一些常用操作比如过滤、遍历等操作 * @author BG235144 * */public class FileUtils {    /**     * 列出指定目录下(包括其子目录)的所有文件     * @param dir     * @throws IOException     */    public static void listDirectory(File dir) throws IOException{        if(!dir.exists()) {            throw new IllegalArgumentException("目录:"+dir+"不存在");        }        if(!dir.isDirectory()) {            throw new IllegalArgumentException(dir+"不是目录");        }        /**         * 返回的是字符串数组,         * 不包含子目录下的内容         *///      String[] filenames = dir.list(); //      for(String filename:filenames) {//          System.out.println(dir+"\\"+filename);//      }        /**         * 如果要遍历子目录下的内容就要构造成File对象做递归操作,         * File提供了直接返回File对象的api,         * 返回的是直接子目录(文件)的对象         */        File[] files = dir.listFiles();//      for(File file:files) {//          System.out.println(file);//      }        if(files!=null && files.length>0) {            for(File file:files) {                if(file.isDirectory()) {                    /**                     * 递归                     */                    listDirectory(file);                }else {                    System.out.println(file);                }            }        }    }}

3 RandomAccessFile类的使用

3.1 RandomAccessFile基本操作

RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,可以访问文件的任意位置

RandomAccessFile 读写过程:
1. Java文件模型:
在硬盘上的文件是byte byte byte存储,是数据的集合
2. 打开文件:
有两种模式”rw”(读写)”r”(只读)
RandomAccessFile raf = new RandomAccessFile(file,”rw”);
文件指针,pointer = raf.getFilePointer(),
打开文件时指针在开头 pointer = 0;
3. 写方法:
raf.write(int)—>只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
4. 读方法:
文件读写完成以后一定要关闭(oracle官方说明)

public static void main(String[] args) throws IOException{    File demo = new File("D:\\javaio");    if(!demo.exists()) {        demo.mkdir();    }    File file = new File(demo,"raf.dat");    if(!file.exists()) {        file.createNewFile();    }    RandomAccessFile raf = new RandomAccessFile(file,"rw");    // 指针位置    System.out.println(raf.getFilePointer());    /**     * java中char是2个字节,     * 只写最后边一个字节进去     */    raf.write('A');     System.out.println(raf.getFilePointer());    raf.write('B');    /**     * 用write方法每次只能写一个字节,     * 如果要把i写进去就得写4次     */    int i = 0x7fffffff;    raf.write(i>>>24); // 高8位    raf.write(i>>>16);    raf.write(i>>>8);    raf.write(i);    System.out.println(raf.getFilePointer());    // 可以直接写一个int    raf.writeInt(i);    /**     * 可以直接写一个中文汉子,     */    String s = "中";    byte[] gbk = s.getBytes("gbk");    /**     * 可以写入字节数组     */    raf.write(gbk);    System.out.println(raf.length());    /**     * 读文件,必须把指针移到头部     */    raf.seek(0);    /**     * 一次性读取,把文件中的内容都读到字节数组中     */    byte[] buf = new byte[(int)raf.length()];    raf.read(buf);    System.out.println(Arrays.toString(buf));    String s1 = new String(buf,"gbk");    System.out.println(s1);    /**     * 以16进制方式输出     */    for(byte b:buf) {        System.out.print(Integer.toHexString(b & 0xff) + " ");    }    /**     * 关闭     */    raf.close();}

输出

01612[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]AB������中41 42 7f ff ff ff 7f ff ff ff d6 d0 

4 字节流

4.1 字节流之文件输入流FileInputStream-1

这里写图片描述
这里写图片描述
这里写图片描述

public class IOUtil {    /**     * 读取指定文件内容,按照16进制输出到控制台,     * 并且每输出10个byte换行     * @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) {            if(b<=0xf) {                // 单位数前面补0                System.out.println("0");            }            // 将整数b转换为16进制表示的字符串            System.out.print(Integer.toHexString(b) + " ");            if(i++%10 == 0) {                System.out.println();            }        }        in.close();    }}

4.2 字节流之文件输入流FileInputStream-2

/** * 从int中批量读取字节,放入到buf这个字节数组中, * 从第0个位置开始放,最多放buf.length个, * 返回的是读到的字节个数 */public static void printHexByByteArray(String fileName) throws IOException{    FileInputStream in = new FileInputStream(fileName);    /**     * 适宜大小,直到读取全部文件为止     */    byte[] buf = new byte[8*1024];    int bytes = 0;    int j = 1;    while((bytes = in.read(buf,0,buf.length))!=-1) {        for(int i = 0; i < bytes; i ++) {            if((buf[i] & 0xff) <= 0xf) {                System.out.print("0");            }            /**             * byte类型8位,int类型32位,             * 为避免数据转换错误,通过&0xff将高位24位请零             */            System.out.print(Integer.toHexString(buf[i] & 0xff)+" ");            if(j++%10 == 0) {                System.out.println();            }        }    }}

4.3 字节流之文件输出流FileOutputStream

这里写图片描述

public static void main(String[] args) throws IOException{    // TODO Auto-generated method stub    /**     * 参数一:文件     * 参数二:是否在文本后面追加     */    FileOutputStream out = new FileOutputStream("D:\\javaio\\out.dat",true);    out.write('A'); // 写出了'A'的低8位    out.write('B'); // 写出了'B'的低8位    int a = 10; // write 只能写低8位,那么写一个int需要写4次    out.write(a>>>24); // 写入高8位    out.write(a>>>16);    out.write(a>>>16);    out.write(a);    byte[] gbk = "中国".getBytes("gbk");    out.write(gbk); // 可以写出字符数组    out.close();}
/** * 拷贝文件 * @param srcFile * @param destFile * @throws IOException */public static void copyFile(File srcFile,File destFile) throws IOException {    if(!srcFile.exists()) {        throw new IllegalArgumentException("文件" + srcFile + "不存在");    }    if(!srcFile.isFile()) {        throw new IllegalArgumentException(srcFile + "不是文件");    }    if(!destFile.exists()) {        destFile.createNewFile();    }    FileInputStream in = new FileInputStream(srcFile);    FileOutputStream out = new FileOutputStream(destFile);    /**     * 适当的大小,     * 一次一次中转文件,     * 知道文件全部拷贝为止     */    byte[] buf = new byte[8*1024];    int b;    while((b = in.read(buf, 0, buf.length))!=-1) {        out.write(buf, 0, b);        out.flush(); // 最好加上    }    in.close();    out.close();}

4.4 字节流之数据输入输出流

DataOutputStream/DataInputStream
对“流”功能的扩展,可以更加方便的读取int,long,字符等类型数据 DataOutputStream
writeInt()/writeDouble()/writeUTF()

public static void main(String[] args) throws IOException{    // TODO Auto-generated method stub    String file = "D:\\javaio\\dos.dat";    /**     * FileOutputStream 包装成  DataOutputStream 目的就是为了用它的 write 方法,     * 写出基本数据类型的时候更加方便     */    DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));    dos.writeInt(10);    dos.writeInt(-10);    dos.writeLong(10l);    dos.writeDouble(10.5);    // 采用 utf-8 编码写出    dos.writeUTF("中国");    // 采用 utf-16be 编码写出    dos.writeChars("中国");    dos.close();    /**     * FileInputStream 包装成 DataInputStream 目的就是为了用 read 方法,     * 读取基本数据类型的时候更加方便     */    DataInputStream dis = new DataInputStream(new FileInputStream(file));    int i = dis.readInt();    System.out.println(i);    i = dis.readInt();    System.out.println(i);    long j = dis.readLong();    System.out.println(j);    double h = dis.readDouble();    System.out.println(h);    String k = dis.readUTF();    System.out.println(k);    dis.close();}

4.5 字节缓冲流

8) BufferedInputStream & BufferedOutputStream 这两个流类为 IO 提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了 IO 的性能,从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
FileOutputStream —> write() 方法相当于一滴一滴地把水“转移”过去,

DataOutputStream—>writeXxx() 方法会方便一些,相当于一瓢一瓢把水“转移”过去,
BufferedOutputStream—>write()方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入缸中

FileInputStream/FileOutputStream(需要时间:20多万ms)
单字节,不带缓冲,进行文件拷贝

/**
* 单字节,不带缓冲,进行文件拷贝
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileByByte(File srcFile, File destFile) throws IOException{
if(!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在");
}
if(!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件");
}
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
int c;
while((c = in.read())!=-1) {
out.write(c);
out.flush();
}
in.close();
out.close();
}

文件拷贝,字节批量读取(需要时间:7ms,拷贝文件速度最快)

/**
* 文件拷贝,字节批量读取
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileBybuf(File srcFile,File destFile) throws IOException {
if(!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在");
}
if(!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件");
}
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
/**
* 适当的大小,
* 开辟内存,批量读取
* 直到文件全部拷贝为止
*/
byte[] buf = new byte[8*1024];
int b;
while((b = in.read(buf, 0, buf.length))!=-1) {
out.write(buf, 0, b);
out.flush(); // 最好加上
}
in.close();
out.close();
}

DataInputStream/DataOutputStream

public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
String file = "D:\\javaio\\dos.dat";
/**
* FileOutputStream 包装成 DataOutputStream 目的就是为了用它的 write 方法,
* 写出基本数据类型的时候更加方便
*/
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
dos.writeInt(10);
dos.writeInt(-10);
dos.writeLong(10l);
dos.writeDouble(10.5);
// 采用 utf-8 编码写出
dos.writeUTF("中国");
// 采用 utf-16be 编码写出
dos.writeChars("中国");
dos.close();
/**
* FileInputStream 包装成 DataInputStream 目的就是为了用 read 方法,
* 读取基本数据类型的时候更加方便
*/
DataInputStream dis = new DataInputStream(new FileInputStream(file));
int i = dis.readInt();
System.out.println(i);
i = dis.readInt();
System.out.println(i);
long j = dis.readLong();
System.out.println(j);
double h = dis.readDouble();
System.out.println(h);
String k = dis.readUTF();
System.out.println(k);
dis.close();
}

BufferedInputStream/BufferedOutputStream(需要时间10万多ms)
进行文件的拷贝,利用带缓冲的字节流

/**
* 进行文件的拷贝,利用带缓冲的字节流
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileByBuffer(File srcFile, File destFile) throws IOException{
if(!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在");
}
if(!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件");
}
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
int c;
while((c = bis.read())!=-1) {
bos.write(c);
/**
* 带缓冲,必须刷新缓冲区
*/
bos.flush();
}
bis.close();
bos.close();
}

5 字符流

5.1 字节字符转换流

1)编码问题
2)认识文本和文本文件
java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码),文本是byte byte byte…的数据序列
文本文件是文本(char)按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果
3)字符流(输入流的抽象类:Reader、输出流的抽象类:Writer)
字符流的处理方式:读/写一次处理一个字符(可能是英文字符、中文字符、可能是不同编码的… 所占大小不同)
字符的底层,任然是基本的字节序列
字符流的基本实现
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,按照编码处理

原创粉丝点击