JAVA基础之IO操作

文件 - File类

  • File对象
1、用来将文件或者文件夹封装成对象
2、方便对文件与文件夹的属性信息进行操作
3、File对象可以作为参数传递给流的构造函数
public class Test {
    public static void main(String[] args) {
        File f = new File("e:\\");
        System.out.println(new File("e:\\demo.txt"));
        System.out.println(new File("e:\\", "demo.txt"));
        System.out.println(new File(f, "demo.txt"));
        System.out.println(new File("e:" + File.separator + "demo.txt"));
    }
}
/** 输出
e:\demo.txt
e:\demo.txt
e:\demo.txt
e:\demo.txt
*/
  • File对象 - 常见功能

1.获取

  1.1 获取文件名称 - getName()
  1.2 获取文件路径 - getPath()/getAbsolutePath() 
  1.3 获取文件大小 - length()
  1.4 获取文件修改时间 - lastModified() 

2.创建与删除

  2.1 创建文件 - createNewFile():和输出流不一样,如果文件不存在,则创建,如果文件存在,则不创建
	       - mkdir():创建目录
  2.2 删除文件 - delete():当使用delete()删除目录时,如果不是空文件夹会删除失败
	       - deleteOnExit():在虚拟机终止时,请求删除此抽象路径名表示的文件或目录

3.判断

  3.1 判断是否存在 - exists()
  3.2 判断是否是目录 - isDirectory()
  3.3 判断是否是文件 - isFile()

4.重命名

 4.1 重命名 - renameTo(File dest)

5.列出目录和容器获取

  5.1 获取可用的文件系统根 - listRoots()
  5.2 获取抽象路径名指定的分区大小 - getTotalSpace()
  5.3 获取抽象路径名指定的分区中未分配的字节数 - getFreeSpace()
  5.4 获取抽象路径名指定的分区上可用于此虚拟机的字节数 - getUsableSpace()
  5.5 获取目录中的文件和目录,包含隐藏文件 - String[] list() =>只能通过目录去调用,否则空指针异常,如果目录存在但没有内容,则返回长度为0的数组
  5.6 获取目录中按照特定过滤器过滤后的文件和目录 - String[] list(FilenameFilter filter)
  • 实例
public class Test {
    public static void main(String[] args) throws IOException {
        File file = new File("demo.txt");
        File absFile = new File("C:\\Users\\Administrator\\workspace\\HelloJava\\demo.txt");

        String name = file.getName();
        String absPath = file.getAbsolutePath();
        String path = file.getPath();
        long length = file.length();

        long time = file.lastModified();
        String lastModifiedTime = getTime(time);

        String parentPath = file.getParent();
        String absFileParentPath = absFile.getParent();

        System.out.println("parentPath:" + parentPath + " ==> absFileParentPath:"
                + absFileParentPath);

        // 删除创建文件
        file.delete();
        file.createNewFile();
        System.out.println("lastModifiedTime:" + lastModifiedTime + " ==> new:"
                + getTime(file.lastModified()));

        File dir = new File("test\\a\\b\\c");
        // 创建目录
        dir.mkdir();
        dir.delete(); // 如果c不是空文件夹,将删除失败;并且只能删除c文件夹

        // 文件或目录是否存在
        boolean isExist = file.exists();
        boolean isAbsolute = file.isAbsolute();
        boolean isFile = file.isFile();
        boolean isDir = dir.isDirectory();

        File dest = new File("text.txt");
        // 重命名
        file.renameTo(dest);
        // 剪切
        dest.renameTo(new File("e:\\abc.txt"));

        File[] files = File.listRoots();
        for (File f : files) {
            long free = f.getFreeSpace();
            long total = f.getTotalSpace();
            // 返回此抽象路径名指定的分区上可用于此虚拟机的字节数
            long usable = f.getUsableSpace();
        }

        // list方法只能使用目录去调用,文件调用会返回null
        String[] list = absFile.list();
        System.out.println(file.list());

        File workspace = new File("C:\\Users\\Administrator\\workspace\\HelloJava");
        list = workspace.list(new SuffixFilter(".txt"));
        for (String string : list) {
            System.out.println(string);
        }

        files = workspace.listFiles(new FilterByHidden());
        for (File f : files) {
            System.out.println(f);
        }

    }

    private static String getTime(long time) {
        Date date = new Date(time);
        DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
        return format.format(date);
    }
}

class SuffixFilter implements FilenameFilter {
    private String suffix = null;

    public SuffixFilter(String suffix) {
        super();
        this.suffix = suffix;
    }

    public boolean accept(File dir, String name) {
        return name.endsWith(suffix);
    }
}

class FilterByHidden implements FileFilter {
    public boolean accept(File pathname) {
        return pathname.isHidden();
    }
}

/**
* 输出 : 
parentPath:null ==> absFileParentPath:C:\Users\Administrator\workspace\HelloJava
lastModifiedTime:16-2-17 下午10:11 ==> new:16-2-17 下午10:18
null
demo.txt
fileWriter.txt
text.txt
*/
// 深度遍历目录
public class Test {
    public static void main(String[] args) throws IOException {
        File dir = new File("C:\\Users\\Administrator\\workspace\\HelloJava\\bin");
        listAll(dir, 0);
        deleteAll(dir);
    }

    // 深度遍历目录
    private static void listAll(File dir, int level) {
        File[] files = dir.listFiles();
        level++;
        for (int i = 0; i < files.length; i++) {
            if (files[i].isDirectory()) {
                // 递归调用,一个功能在被重复使用,并每次使用时参与运算的结果和上一次调用有关
                // 注意:
                // 1.递归一定明确条件,否则容易栈溢出
                // 2.注意一下递归次数
                listAll(files[i], level);
            } else {
                System.out.println(level + ":" + files[i].getAbsolutePath());
            }
        }
    }

    // 删除目录,需要从里往外删除
    private static void deleteAll(File dir) {
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            if (files[i].isDirectory()) {
                deleteAll(files[i]);
            } else {
                files[i].delete();
            }
        }
        dir.delete();
    }
}
// 文件切割、合并
public class Test {
    private static final int SIZE = 1024;

    public static void main(String[] args) throws IOException {
        File file = new File("e:\\tone.mp3");
        spitFile(file);

        mergeFile(new File("e:\\test"));
    }

    // 文件切割
    private static void spitFile(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);

        Properties prop = new Properties();

        byte[] buff = new byte[SIZE * 100];

        FileOutputStream fos = null;

        int len = 0;
        int count = 1;

        File dir = new File("e:\\test");
        if (!dir.exists()) {
            dir.mkdir();
        }

        while ((len = fis.read(buff)) != -1) {
            fos = new FileOutputStream(new File(dir, (count++) + ".part"));
            fos.write(buff, 0, len);
            fos.close();
        }

        // 将文件切割信息保存到属性中
        prop.setProperty("count", count + "");
        prop.setProperty("name", file.getName());

        // 将属性保存到.prop 配置信息中
        fos = new FileOutputStream(new File(dir, (count++) + ".prop"));
        prop.store(fos, "save file prop");

        fos.close();
        fis.close();
    }

    // 文件合并
    private static void mergeFile(File dir) throws IOException {
        File[] files = dir.listFiles(new SuffixFilter(".prop"));

        if (files.length != 1) {
            throw new RuntimeException("Filename not match..");
        }

        File config = files[0];

        // 获取配置文件信息
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream(config);

        prop.load(fis);

        String name = prop.getProperty("name");
        int count = Integer.parseInt(prop.getProperty("count"));

        File[] parts = dir.listFiles(new SuffixFilter(".part"));
        if (parts.length != count - 1) {
            throw new RuntimeException("Part length not match..");
        }

        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();

        for (int i = 1; i < count; i++) {
            al.add(new FileInputStream(new File(dir, i + ".part")));
        }

        Enumeration<FileInputStream> en = Collections.enumeration(al);
        SequenceInputStream sis = new SequenceInputStream(en);

        FileOutputStream fos = new FileOutputStream(new File(dir, name));

        byte[] buff = new byte[SIZE * 100];
        int len = 0;

        while ((len = sis.read(buff)) != -1) {
            fos.write(buff, 0, len);
        }

        fos.close();
        sis.close();
    }
}

class SuffixFilter implements FilenameFilter {
    private String suffix = null;

    public SuffixFilter(String suffix) {
        super();
        this.suffix = suffix;
    }

    public boolean accept(File dir, String name) {
        return name.endsWith(suffix);
    }
}

流分类

  • 按流向分为:输入流与输出流
输入流和输出流相对于内存设备而言
输入:将外设中的数据读取到内存中
输出:将内存中国的数据写入到外设中
  • 按照操作数据分为:字节流与字符流
字符流的由来:字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字,再对这个文字进行操作
简单说:字符流 = 字符流+编码表
IO体系的子类都以父类名作为后缀,而且子类名的前缀就是该对象的功能

字符流 - Reader/Writer

如果要操作文字数据,建议优先考虑字符流,而且要将数据从内存写到硬盘上,要使用字符流中的输出流-Writer,硬盘的数据基本体现是文件
Java Base Study Note Url 18 1.jpg
Java Base Study Note Url 18 2.jpg
  • 字符流 - 写入文件(FileWriter)
public class Test {
    // 换行
    private static final String LINE_SEPARATOR = System.lineSeparator();

    public static void main(String[] args) throws IOException {
        File file = new File("e:\\fileWriter.txt");
        fileWrite(file, "FileWriter");
    }

    private static void fileWrite(File path, String input) throws IOException {
        // 如果文件不存在,则创建;如果文件存在,则覆盖
        FileWriter writer = new FileWriter(path);
        //FileWriter writer = new FileWriter(path, true); //续写构造函数
	// FileWriter(File file, boolean append):续写
        // 写入数据
        writer.write(input + LINE_SEPARATOR);
        // 进行刷新,将数据直接写到目的地中
        writer.flush();
        writer.append(input + LINE_SEPARATOR);
        // 在关闭前会调用flush()刷新缓冲池中的数据到目的地
        writer.close();
    }
}
  • 字符流 - 读取文件(FileReader)
public class Test {
    public static void main(String[] args) {
        File file = new File("e:\\demo.txt");
        System.out.println(readFile(file));
    }

    private static String readFile(File path) {
        FileReader reader = null;
        StringBuilder builder = new StringBuilder();
        try {
            reader = new FileReader(path);
            int ch = 0;
            while ((ch = reader.read()) != -1) {
                builder.append((char) ch);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null)
                    reader.close();
            } catch (IOException e) {
                throw new RuntimeException("Close fail!");
            }
        }
        return builder.toString();
    }
}
  • 字符流 - 文件读写操作(复制)
public class Test {
    public static void main(String[] args) {
        File in = new File("e:\\demo.txt");
        File out = new File("e:\\copy.txt");
        copyFile(in, out);
    }

    private static void copyFile(File in, File out) {
        FileReader reader = null;
        FileWriter writer = null;

        try {
            /* 效率较低
            reader = new FileReader(in);
            writer = new FileWriter(out);
            int ch = 0;
            while ((ch = reader.read()) != -1) {
                writer.write(ch);
            }
            */
            reader = new FileReader(in);
            writer = new FileWriter(out);
            char[] ch = new char[1024];
            int len = 0;
            while ((len = reader.read(ch)) != -1) {
                writer.write(ch, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("Close fail!");
            }
        }
    }
}
  • 字符流 - 缓冲区(BufferedWriter/BufferedReader)
特点:
 1. 缓冲区的出现提供了对数据的读写效率
 2. 缓冲区要结合流才可以使用
 3. 在流的基础上对流的功能进行了增强
BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
  public String readLine():读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。

BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
  public void newLine():写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符。 
BufferedReader 使用了装饰模式
装饰设计模式:对一组对象的功能进行增强时,就可以使用该模式进行问题的解决

装饰比继承灵活
特点:装饰类和被装饰类都必须所属同一个接口或者父类
public class Test {
    public static void main(String[] args) {
        File in = new File("e:\\demo.txt");
        File out = new File("e:\\copy.txt");
        copyFile(in, out);
    }

    private static void copyFile(File in, File out) {
        FileReader reader = null;
        BufferedReader bufReader = null;

        FileWriter writer = null;
        BufferedWriter bufWriter = null;

        try {
            reader = new FileReader(in);
            bufReader = new BufferedReader(reader);

            writer = new FileWriter(out);
            bufWriter = new BufferedWriter(writer);

            String line = null;
            while ((line = bufReader.readLine()) != null) {
                bufWriter.write(line);
                bufWriter.newLine();
                bufWriter.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufReader != null) {
                    bufReader.close();
                }
                if (bufWriter != null) {
                    bufWriter.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("Close fail!");
            }
        }
    }
}
// 自定义BufferedReader
public class Test {
    public static void main(String[] args) {
        File file = new File("e:\\demo.txt");
        readFile(file);
    }

    private static void readFile(File file) {
        FileReader reader = null;
        CustomBufferedReader bufReader = null;

        try {
            reader = new FileReader(file);
            bufReader = new CustomBufferedReader(reader);

            String line = null;
            while ((line = bufReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufReader != null) {
                    bufReader.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("Close fail!");
            }
        }
    }
}

class CustomBufferedReader {
    char[] buffer = new char[1024];
    Reader reader = null;
    private int count = 0;
    private int pos = 0;

    CustomBufferedReader(Reader reader) {
        this.reader = reader;
    }

    public int read() throws IOException {
        if (count == 0) {
            count = reader.read(buffer);
            pos = 0;
        }
        if (count < 0) {
            return -1;
        }
        char ch = buffer[pos++];
        count--;
        return ch;
    }

    public String readLine() throws IOException {
        StringBuilder sb = new StringBuilder();
        int ch = 0;
        while ((ch = read()) != -1) {
            if (ch == '\r')
                continue;
            if (ch == '\n')
                return sb.toString();
            sb.append((char) ch);
        }
        if (sb.length() > 0)
            return sb.toString();
        return null;
    }

    public void close() throws IOException {
        reader.close();
    }
}
  • 字符流 - 缓冲区(BufferedReader子类:LineNumberReader)
public class Test {
    public static void main(String[] args) {
        File file = new File("e:\\demo.txt");
        readFile(file);
    }

    private static void readFile(File file) {
        FileReader reader = null;
        LineNumberReader bufReader = null;

        try {
            reader = new FileReader(file);
            bufReader = new LineNumberReader(reader);

            String line = null;
            bufReader.setLineNumber(2);
            while ((line = bufReader.readLine()) != null) {
                System.out.println(bufReader.getLineNumber() + ":" + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufReader != null) {
                    bufReader.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("Close fail!");
            }
        }
    }
}
  • 转换流 - InputStreamReader/OutputStreamWriter
转换流 - 字节转字符
InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
转换流 - 字符转字节
OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
public class Test {
    public static void main(String[] args) {
        try {
            readFromKeyboard();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void readFromKeyboard() throws IOException {
        /*
        InputStream is = System.in;
        // 字节流转字符流
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader reader = new BufferedReader(isr);

        OutputStream os = System.out;
        // 字符流转字节流
        OutputStreamWriter osw = new OutputStreamWriter(os);
        BufferedWriter writer = new BufferedWriter(osw);
        */
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

        String line = null;
        while ((line = reader.readLine()) != null) {
            if (line.equals("over")) {
                break;
            }
            writer.write(line.toUpperCase());
            writer.newLine();
            writer.flush();
        }
    }
}

字节流 - InputStream/OutputStream

Java Base Study Note Url 18 3.jpg
Java Base Study Note Url 18 4.jpg
  • 字节流操作文件不需要缓冲,直接写入到了目的文件中
public class Test {
    public static void main(String[] args) {
        File file = new File("e:\\demo.txt");
        try {
            writeFile(file, "Android" + System.lineSeparator() + "Java");
            readFile(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void readFile(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);

        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            System.out.println(new String(buf, 0, len));
        }

        /* 尽量少用available(),文件过大容易造成内存溢出
        byte[] buf = new byte[fis.available()];
        fis.read(buf);
        System.out.println(new String(buf));
        */

        fis.close();
    }

    private static void writeFile(File file, String in) throws IOException {
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(in.getBytes());
        fos.close();
    }
}
  • 使用字节流拷贝图片
public class Test {
    public static void main(String[] args) {
        try {
            copyPic_1();
            copyPic_2();
            copyPic_3();
            copyPic_4();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void copyPic_1() throws IOException {
        FileInputStream fis = new FileInputStream(new File("e:\\pic.jpg"));
        FileOutputStream fos = new FileOutputStream(new File("e:\\pic_1.jpg"));

        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        fos.close();
        fis.close();
    }

    // 不建议使用,available()会影响性能
    private static void copyPic_2() throws IOException {
        FileInputStream fis = new FileInputStream(new File("e:\\pic.jpg"));
        FileOutputStream fos = new FileOutputStream(new File("e:\\pic_2.jpg"));

        byte[] buf = new byte[fis.available()];
        fis.read(buf);
        fos.write(buf);

        fos.close();
        fis.close();
    }

    // 不会使用,毫无效率,慢得不行!
    private static void copyPic_3() throws IOException {
        FileInputStream fis = new FileInputStream(new File("e:\\pic.jpg"));
        FileOutputStream fos = new FileOutputStream(new File("e:\\pic_3.jpg"));

        int ch = 0;
        while ((ch = fis.read()) != -1) {
            fos.write(ch);
        }
        fos.close();
        fis.close();
    }

    private static void copyPic_4() throws IOException {
        FileInputStream fis = new FileInputStream(new File("e:\\pic.jpg"));
        BufferedInputStream bufis = new BufferedInputStream(fis);

        FileOutputStream fos = new FileOutputStream(new File("e:\\pic_4.jpg"));
        BufferedOutputStream bufos = new BufferedOutputStream(fos);

        int ch = 0;
        while ((ch = bufis.read()) != -1) {
            bufos.write(ch);
        }
        bufis.close();
        bufos.close();
    }
}
  • 键盘录入 - System.in
public class Test {
    public static void main(String[] args) {
        try {
            readFromKeyboard();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void readFromKeyboard() throws IOException {
        InputStream is = System.in;
        StringBuilder sb = new StringBuilder();

        int ch = 0;
        // read()是阻塞方法
        while ((ch = is.read()) != -1) {
            if (ch == '\r') {
                continue;
            }
            if (ch == '\n') {
                String tmp = sb.toString();
                if (tmp.equals("over")) {
                    break;
                }
                System.out.println(tmp.toUpperCase());
                sb.delete(0, sb.length());
            } else {
                sb.append((char) ch);
            }
        }
        //从System.in获取的流对象只有一个,不需要关闭流,该流会随系统自动关闭
        //关闭了就很难获取到
        //is.close();
    }
}
  • 对象的序列化与反序列化 - ObjectInputStream/ObjectOutputStream
通过在流中使用文件可以实现对象的持久存储
ObjectOutputStream:将 Java 对象的基本数据类型和图形写入 OutputStream,即将对象写入文件中

ObjectInputStream:对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化,即从文件中读取对象
public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        File file = new File("e:\\person.object");

        writeObj(new Person("zhangsan", 23, 1000, "xiaozhang"), file);
        readObj(file);
    }

    // 保存对象到硬盘上,保存的对象需要序列化
    private static void writeObj(Person person, File file) throws IOException {
        ObjectOutputStream oop = new ObjectOutputStream(new FileOutputStream(file));
        // 对象序列话。被序列话的对象必须实现Serializable接口
        oop.writeObject(person);
        oop.close();
    }

    private static void readObj(File file) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        // 对象的反序列化
        Person person = (Person) ois.readObject();

        System.out.println(person.name + " : " + person.age + " : " + person.money + " : "
                + person.nike);

        ois.close();
    }
}

/**
 * Serializable:用于给被序列号的类加入ID号,用于判断类和对象是否是同一版本
 */
class Person implements Serializable /** 标记接口 */
{
    // 通过该ID 判断对象和类是否是同一版本
    private static final long serialVersionUID = 2L;

    public String name;
    public int age;

    // static 不能被序列化保存到硬盘上,因为static不属于对象
    public static int money;

    // transient:非static的,不被序列化可以使用该关键字
    public transient String nike;

    public Person(String name, int age, int money, String nike) {
        this.name = name;
        this.age = age;
        this.money = money;
        this.nike = nike;
    }
}
  • 管道流 - PipedInputStream/PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用
不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁
public class Test {
    public static void main(String[] args) throws IOException {
        PipedInputStream input = new PipedInputStream();
        PipedOutputStream output = new PipedOutputStream();

        input.connect(output); // 关联起来
        // PipedOutputStream output = new PipedOutputStream(input); //关联起来

        new Thread(new Input(input)).start();
        new Thread(new Out(output)).start();
    }

}

class Input implements Runnable {
    private PipedInputStream in;

    public Input(PipedInputStream in) {
        this.in = in;
    }

    public void run() {
        try {
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            String s = new String(buf, 0, len);
            System.out.println("s:" + s);
            in.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

class Out implements Runnable {
    private PipedOutputStream out;

    public Out(PipedOutputStream out) {
        this.out = out;
    }

    public void run() {
        try {
            out.write("PipedOutputStream ...".getBytes());
            out.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

// 输出:
// s:PipedOutputStream ...
  • 操作基本数据类型 - DataInputStream/DataOutputStream
应用程序可以使用数据输出流写入稍后由数据输入流读取的数据
DataInputStream 对于多线程访问不一定是安全的
public class Test {
    public static void main(String[] args) throws IOException {
        File file = new File("e:\\data.txt");
        writeData(file);
        readData(file);
    }

    private static void writeData(File file) throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
        dos.writeUTF("Hello DataOutputStream");
        dos.close();
    }

    private static void readData(File file) throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream(file));
        String utf = dis.readUTF();
        System.out.println(utf);
    }
}

// 输出:
// Hello DataOutputStream
  • 操作字节数组 - ByteArrayInputStream/ByteArrayOutputStream
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节
关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException(因为该对象并没有操作底层资源)
public class Test {
    public static void main(String[] args) throws IOException {
        ByteArrayInputStream bis = new ByteArrayInputStream("ByteArrayInputStream".getBytes());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        int ch = 0;

        while ((ch = bis.read()) != -1) {
            bos.write(ch);
        }

        System.out.println(bos.toString());
    }

}

// 输出:
// ByteArrayInputStream

随机访问文件 - RandomAccessFile

支持对随机访问文件的读取和写入
1.随机访问文件,自身具备读写的方法
2.通过skipBytes(int x),seek(int x)来达到随机访问
  • 特点
1. 该对象既能读,又能写
2. 该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素
3. 可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置
4. 该对象就是字节输入流和输出流进行了封装
5. 该对象的源或者目的只能是文件。通过构造函数可以看出
public class Test {
    public static void main(String[] args) throws IOException {
        File file = new File("e:\\random.txt");
        writeFile(file);
        randomWrite(file);
        randomRead(file);
    }

    private static void writeFile(File file) throws IOException {
        // 如果文件不存在,则创建;如果文件存在,则不创建
        RandomAccessFile raf = new RandomAccessFile(file, "rw");
        raf.write("zhangsan".getBytes());
        raf.writeInt(22);

        raf.write("lisi".getBytes());
        raf.writeInt(25);

        raf.close();
    }

    private static void randomWrite(File file) throws IOException {
        // 如果文件不存在,则创建;如果文件存在,则不创建
        RandomAccessFile raf = new RandomAccessFile(file, "rw");

        raf.seek(12); // 随机写入,只要指定指针的位置即可
        raf.write("wangwu".getBytes());
        raf.writeInt(25);

        raf.close();
    }

    // 可以用于多线程写入
    private static void randomRead(File file) throws IOException {
        RandomAccessFile raf = new RandomAccessFile(file, "r");
        // 通过seek设置指针位置
        raf.seek(12); // 随机读取,只要指定指针的位置即可

        byte[] buf = new byte[6];
        raf.read(buf);

        System.out.println("name:" + new String(buf) + " age:" + raf.readInt());
        raf.close();
    }
}

// 输出:
// name:wangwu age:25

异常处理 - IOException

public class Test {
    // 换行
    private static final String LINE_SEPARATOR = System.lineSeparator();

    public static void main(String[] args) {
        File file = new File("h:\\fileWriter.txt");
        writeFile(file, "FileWriter");
    }

    private static void writeFile(File path, String input) {
        FileWriter writer = null;
        try {
            writer = new FileWriter(path);
            writer.append(input + LINE_SEPARATOR);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null)
                    writer.close();
            } catch (IOException e) {
                throw new RuntimeException("Close fail!");
            }
        }
    }
}

// java.io.FileNotFoundException

编码

  • 常见编码表
ASCII:美国标准信息交换吗  =>用一个字节的7位可以表示

ISO8859-1:拉丁码表。欧洲码表 =>用一个字节的8位表示

GB2312:中国的中文编码表
GBK:中国的中文编码表升级

Unicode:国际标准码,融合了多种文字。 =>所有文字都用两个字节来表示,java语言使用的就是unicode

UTF-8:最多用三个字节来表示一个字符
字符串-->字节数组:编码
字节数组-->字符串:解码
public class Test {
    public static void main(String[] args) throws IOException {
        String str = "你好";
        // 编码
        byte[] buf_gbk = str.getBytes("GBK");
        byte[] buf_utf = str.getBytes("utf-8");

        // 解码
        printBytes(buf_gbk);
        printBytes(buf_utf);
    }

    private static void printBytes(byte[] buf) {
        for (byte b : buf) {
            System.out.print(b + " ");
        }
        System.out.println();
    }

}

// 输出:
// -60 -29 -70 -61 
// -28 -67 -96 -27 -91 -67

流的基本操作规律

  • 转换流
InputStreamReader:字节流到字符流的桥梁。解码。
OutputStreamWriter:字符到字节的桥梁。编码。
  • 流的操作规律
1、明确源和目的
    源:InputStream Reader
  目的:OutputStream Writer

2、明确数据是否是纯文本数据
  源:是纯文本:Reader
            否:InputStream
  目的:是纯文本:Writer
              否:OutputStream

3、明确具体的设备
  源设备:
      硬盘:File
      键盘:System.in
      内存:数组
      网络:Socket流
  目的设备:
      硬盘:File
      控制台:System.out
      内存:数组
      网络:Socket流

4、是否需要其他额外功能
  是否需要高效(缓冲区):是,就加上Buffer
  是否需要转换:是...
  • 什么时候使用转换流?
1. 源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换流作为桥梁。提高对文本操作的便捷。
2. 一旦操作文本涉及到具体的指定的编码表时,必须使用转换流。
  • 转换流的编码解码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"), "gbk");
FileWriter fw = new FileWriter("gbk.txt");
//这两句代码功能是相同的
FileWriter其实就是转换流指定了本地默认码表的体现。而且是这个转换流的子类对象,可以方便操作文本文件

简单说:操作文件的字节流+本机默认的编码表,这是按照默认码表来操作文件的便捷类

如果操作文本文件需要明确具体的编码,FileWriter就不行了,必须用转换流

注意:如果明确指定了编码表的动作,那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表,只能使用其父类OutputStreamWriter。
OutputStreamWriter接收一个字节流对象,既然是操作文件,那么该对象应该是FileOutputStream
public class Test {
    public static void main(String[] args) {
        File file = new File("e:\\demo.txt");
        try {
            writeFile(file, "你好" + System.lineSeparator() + "安卓", "utf-8");
            readFile(file, "gbk");
            readFile(file, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void readFile(File file, String code) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),
                code));
        String line = null;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        reader.close();
    }

    private static void writeFile(File file, String in, String code) throws IOException {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(file), code));
        writer.write(in);
        writer.close();
    }
}

/**输出:
浣犲ソ
瀹夊崜
你好
安卓
*/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值