黑马程序员 Java基础 ---> IO流

来源:互联网 发布:mysql front 注册码 编辑:程序博客网 时间:2024/05/21 14:09

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

IO流

IO流概念
  IO流用来处理设备之间的数据传输
  Java对数据的操作是通过流的方式
  Java用于操作流的类都在IO包中
  流按流向分为两种:输入流,输出流。
  流按操作类型分为两种:字节流与字符流。  字节流可以操作任何数据,字符流只能操作纯字符数据,比较方便。

IO流常用父类
  字节流的抽象父类:
    InputStream ,OutputStream
  字符流的抽象父类:
    Reader , Writer
  由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
  如:InputStream的子类FileInputStream。 
  如:Reader的子类FileReader。
  注意: InputStreamReader 是字符流, 可以从字节流中读取字符

IO程序书写
  使用前,导入IO包中的类
  使用时,进行IO异常处理
  使用后,释放资源

字符流读写文件
  读取文件 
    定义字符流关联指定文件
      FileReader reader = new FileReader("Test.txt");
    读取一个字符,返回int,该字符的码表值
      int ch = reader.read();
    关闭流,释放资源
      reader.close();

  写出文件
    定义字符输出流关联指定文件
      FileWriter writer = new FileWriter("Test.txt");
    写出一个字符,接收int码表值
      writer.write(97);
    关闭流,释放资源
      writer.close();

  注意事项
    文件路径
      定义文件路径时Windows中的目录符号为“\”,但这个符号在Java中是特殊字符,需要转义。
      可以用“\\”或“/”表示。
    读取文件
      读取文件时必须保证文件存在,否则将抛出FileNotFoundException。
    写出文件
      写出时文件如不存在时程序会创建新文件,如文件已存在则会清空原文件内容重新写入。
      如需追加内容可调用FileWriter构造函数FileWriter(String fileName, boolean append),传入true之后则不会清空原有文件

拷贝一个文件 实例

import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class Demo3_CopyFile {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("file/Eminem - I Get Money.mp3");// 定义输入流指向file.txtFileOutputStream fos = new FileOutputStream("file/copy.mp3");// 定义输出流指向copy.txtint x;// 定义一个int变量while ((x = fis.read()) != -1)// 定义循环, 每次读取一个字节, 判断是否不是末尾fos.write(x);// 如果不是末尾, 写出到文件fis.close();// 关闭输入流fos.close();// 关闭输出流}}



字符流缓冲区读写
  自定义缓冲区读写
    为什么定义缓冲区
      由于单个字符读写需要频繁操作文件,所以效率非常低。
      我们可以定义缓冲区将要读取或写出的数据缓存,减少操作文件次数。
  缓冲区读取
    先定义一个数组,然后调用FileReader读取一个数组的方法。
    int read(char[] cbuf)
  缓冲区写出
    将要写出的数据存放在数组中,调用FileWriter方法,一次写出一个数组。
    void write(char[] cbuf, int off, int len)
  内置缓冲区的BufferedReader和BufferedWriter
    Java提供了带缓冲功能的Reader和Writer类:BufferedReader,BufferedWriter
    这两个类都是提供包装功能,需要提供其他流来使用,给其他流增加缓冲功能
    当我们调用BufferedReader读取数据时,程序会从文件中一次读取8192个字符用来缓冲
    当我们调用BufferedWriter写出数据时,程序会先将数据写出到缓冲数组,直到写满8192个才一次性刷出到文件

import java.io.IOException;import java.io.Reader;public class BufferedReader {private char[] buffer = new char[8192];// 缓冲区private Reader reader;// 被包装的流private int index;// 每次读取时返回数据的索引private int length;// 缓冲区中有效数据的个数public BufferedReader(Reader reader) {this.reader = reader;}/* * 该方法可以从流中读取1个字符. 但是内置缓冲区, 效率很高. * 第一次使用该方法的时候, 从流中一次性读取8192个字符, 放在缓冲区中, 返回1个 * 第二次在读取的时候, 不再从文件中读取, 直接把缓冲区中第二个字符返回 * 第三次读取时返回缓冲区中第三个 * ... 以此类推 * 直到缓冲区中所有字符都被返回过, 这时再次从文件中读取8192个字符 */public int read() throws IOException {if (index == 0 || index == length) {// 第一次执行该方法index==0, 缓冲区中所有数据都被返回过时index==lengthlength = reader.read(buffer);// 使用被包装的流, 读取数据到缓冲区, length记住个数index = 0;// 把index指向数组的开头位置}return length == -1 ? -1 : buffer[index++];// 从缓冲区中返回1个}/* * 该方法可以读取一行字符串 * 循环逐个读取字符, 读取一个就判断一下 * 如果不是换行符号就存入一个StringBuilder * 如果是换行符号就结束循环, 把StringBuilder中存储的所有字符一次性返回 */public String readLine() throws IOException {StringBuilder sb = new StringBuilder();int x;while ((x = read()) != -1) {// 循环读取字符if (x == '\r')// 如果是\r, 不存入StringBuilder, 继续读取下一个continue;else if (x == '\n')// 如果是\n, 结束循环break;elsesb.append((char) x);// 不是\r也不是\n, 存入StringBuilder}return x == -1 && sb.length() == 0 ? null : sb.toString();}public void close() throws IOException {reader.close();}}



装饰设计模式(Decorator)
  什么情况下使用装饰设计模式
    当我们需要对一个类的功能进行改进、增强的时候
  装饰模式的基本格式。
    含有被装饰类的引用
    通过构造函数传入被装饰类对象
    和被装饰类含有同样的方法,其中调用被装饰类的方法,对其进行改进、增强
    和被装饰类继承同一个类或实现同一个接口,可以当做被装饰类来使用
  了解BufferedReader、BufferedWriter的原理。
    BufferedReader、BufferedWriter都是装饰类,他们可以装饰一个Reader或Writer,给被装饰的Reader和Writer提供缓冲的功能。
    就像我们用BufferedReader、BufferedWriter装饰FileReader和FileWriter,使用的读写功能还是FileReader和FileWriter的,但给这两个类的读写添加了缓冲功能。
 练习
 模拟一个BufferedReader类。
 模拟一个LineNumberReader类。

字节流
  基本操作与字符流相同
  字节流可以操作任意类型数据
 练习:拷贝一个Jpg文件

字节流缓冲区读写
  自定义缓冲区读写
    原理和字符流相同,都是为了提高效率
    定义数组缓冲数据,一次读取一个数组,一次写出一个数组,减少操作文件的次数
  BufferedInputStream、BufferedOutputStream
    和BufferedReader、BufferedWriter原理相同,都是包装类
    BufferedInputStream、BufferedOutputStream包装InputStream和OutputStream提供缓冲功能

转换流
  字符流与字节流之间的桥梁
  方便了字符流与字节流之间的操作
  字节流中的数据都是字符时,转成字符流操作更高效
  练习:转换System.in

标准输入输出流
  System类中的成员变量:in,out。
  它们各代表了系统标准的输入和输出设备。
  默认输入设备是键盘,输出设备是显示器。
  System.in的类型是InputStream.
  System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.
  练习:通过修改标准输入输出流,使用System.in和System.out拷贝文件

流基本应用小节
  流是用来处理数据的。
 处理数据时,一定要先明确数据源,或者数据目的地
 数据源可以是文件,可以是键盘或者其他设备。
 数据目的地可以是文件、显示器或者其他设备。
 而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理、转换处理等。

FileInputStream实例

import java.io.FileInputStream;import java.io.IOException;public class Demo1_FileInputStream {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("day19-笔记.txt");// 创建一个输入流, 关联指定文件int b;// 该变量用来记住读取到的字节数据while ((b = fis.read()) != -1)// 每次读取一个字节, 判断是否是-1(文件末尾)System.out.print((char) b);// 如果不是-1就把这个字节转为字符打印fis.close();// 关闭流, 释放资源}}


FileOutputStream实例

import java.io.FileOutputStream;import java.io.IOException;public class Demo2_FileOutputStream {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("file/test.txt");// 定义输出流指向文件. 文件不存在就创建, 存在就清空.fos.write(97);// 写出1个字节fos.write(98);fos.write(99);fos.close();// 关闭流, 释放资源}}



 File类
 

1.什么是File
  一个File对象代表一个路径, 这个路径可以是文件也可以是文件夹
  该类可以对一个路径进行各种操作, 例如: 判断是否存在, 创建新文件, 删除文件, 改名
 2.创建对象
  new File(String) 通过指定一个路径名创建一个File对象, 路径名可以是绝对路径也可以是相对路径, 可以是文件也可以是文件夹, 甚至可以是一个不存在的路径
  new File(String, String) 通过指定父级路径和子级路径创建一个File对象, 父级路径末尾有没有"/"都可以
  new File(File, String) 通过指定父级路径和自己路径创建一个File对象, 父级路径也可以是一个File对象
 3.绝对路径和相对路径
  绝对路径: 以盘符开始, 无论在任何环境下都是找相同的一个路径.
  相对路径: 不以盘符开始, 在不同的环境下相对于不同的路径. Eclipse中运行时相对于工程根目录, cmd中运行时相对于当前目录.
4.常用方法
  exists()         判断是否存在
  delete()         删除文件或文件夹, 文件夹只能删空的
  length()        文件大小, 文件夹不能直接获取
  lastModified()      文件的最后修改时间
  renameTo()       改名, 也可以改路径
  getAbsolutePath()    获取绝对路径
  getAbsoluteFile()     获取绝对路径封装成的File对象
  getName()        获取文件名
  getParent()       获取父级路径名
  getUsableSpace()    可用空间
  getTotalSpace()     总空间
  createNewFile()     创建新文件
  mkdir()         创建文件夹, 只能创建一个, 父级路径不存在的话不能创建
  mkdirs()        创建文件夹, 一次可以创建多个, 父级路径如果不存在会一起创建
  isFile()         判断是否是文件
  isDirectory()       判断是否是文件夹
  isAbsolute()       判断是否是绝对路径
  listFiles()        获取文件夹中的所有子文件(包括子文件夹). 如果是空文件夹, 会得到一个length为0的数组. 如果是文件, 则会得到null.

常用方法演示

import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;@SuppressWarnings("unused")public class Demo3_FileMethod {public static void main(String[] args) throws IOException {//demo1();//demo2();//demo3();//demo4();//demo5();//demo6();//demo7();//demo8();//demo9();//demo10();}private static void demo10() {File f1 = new File("day21-笔记.txt");File f2 = new File("F:/xxx.txt");f1.renameTo(f2);// 改名, 不只能该文件的名字, 路径也能改}private static void demo9() {File f1 = new File("day21-笔记.txt");long ms = f1.lastModified();Date date = new Date(ms);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(sdf.format(date));}private static void demo8() {File f1 = new File("day21-笔记.txt");System.out.println(f1.length());File f2 = new File("src");System.out.println(f2.length());// 文件夹不能直接获取大小}private static void demo7() {File file = new File("day21-笔记.txt");System.out.println(file.getFreeSpace());// 当前盘符剩余空间System.out.println(file.getUsableSpace());// 当前盘符可用空间System.out.println(file.getTotalSpace());// 当前盘符总空间}private static void demo6() {File file = new File("day21-笔记.txt");System.out.println(file.getName());// 最后一个/右边的内容System.out.println(file.getParent());// 最后一个/左边的内容System.out.println(file.getAbsoluteFile().getParent());}private static void demo5() {File f1 = new File("xxx.txt");File f2 = new File("dir");System.out.println(f1.delete());// 删除文件System.out.println(f2.delete());// 删除文件夹(只能删空的)}private static void demo4() {File file = new File("dir/a/b");//System.out.println(file.mkdir());// 创建文件夹(单个)System.out.println(file.mkdirs());// 创建文件夹(多个)}private static void demo3() throws IOException {File file = new File("xxx.txt");System.out.println(file.createNewFile());// 创建新文件}private static void demo2() {File file = new File("day21-笔记.txt");System.out.println("file.isAbsolute(): " + file.isAbsolute());System.out.println("file.isDirectory(): " + file.isDirectory());System.out.println("file.isFile(): " + file.isFile());System.out.println("file.isHidden(): " + file.isHidden());}private static void demo1() {File file = new File("day21-笔记.txt");file.setReadable(false);file.setWritable(false);file.setExecutable(false);System.out.println(file.canRead());System.out.println(file.canWrite());System.out.println(file.canExecute());}}


 

 

Fill应用实例

import java.io.BufferedReader;import java.io.File;import java.io.IOException;import java.io.InputStreamReader;/* * 从键盘输入获取一个文件夹路径 * 判断用户输入的路径是否存在, 如果不存在给予提示, 并重新输入 * 判断用户输入的路径是否是文件夹路径, 如果是文件路径也要给予提示, 并重输 * 如果输入的是一个已存在的文件夹路径, 提示输入成功 */public class Exercise1 {public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));// 创建一个BufferedReaderSystem.out.println("请输入一个文件夹路径:");while (true) {File file = new File(br.readLine());// 读取一行, 封装成File对象if (!file.exists())// 判断如果不存在System.out.println("您输入的路径不存在, 请重新输入:");else if (file.isFile())// 判断如果是文件路径System.out.println("您输入的是文件路径, 请重新输入一个文件夹路径:");else {// 如果输入的是一个已存在的文件夹路径System.out.println("输入成功!");break;}}}}



递归

  函数自己调用自己。
  注意:递归时一定要明确结束条件。
  应用场景:
   当某一功能要重复使用时。


列出一个文件夹下所有的子文件夹以及子文件,按层级显示。

import java.io.File;public class Exercise2 {public static void main(String[] args) {printSubfile(new File("F:/Itcast/20130418_JavaSE/Code/day21"));}public static void printSubfile(File dir) {// 打印一个文件夹下的所有子文件File[] arr = dir.listFiles();// 获取所有子文件for (File subfile : arr) {// 循环遍历System.out.println(subfile.getName());// 打印每个子文件的名字if (subfile.isDirectory())// 如果是文件夹printSubfile(subfile);// 递归, 再打印这个子文件夹下的所有子文件}}}


统计一个带内容的文件夹的大小。

import java.io.File;public class Exercise4 {public static void main(String[] args) {System.out.println(getDirLength(new File("src")));System.out.println(getDirLength(new File("F:/Itcast/20130418_JavaSE/Code")));}public static long getDirLength(File dir) {// 统计文件夹大小int length = 0;// 定义变量, 用来统计文件夹大小File[] arr = dir.listFiles();// 获取所有子文件for (File subfile : arr) {// 遍历子文件if (subfile.isFile())// 如果是文件length += subfile.length();// 直接累加 length += ...length()else// 如果是文件夹length += getDirLength(subfile);// 递归调用计算文件夹大小, 累加 length += getDirLength(...)}return length;}}


IO包中的其他类
 序列流
SequenceInputStream
可以将多个字节输入流整合成一个流,在使用这个流读取的时候,读到第一个流的末尾时继续读第二个,第二个读到末尾则继续读第三个,以此类推,直到读到最后一个流的末尾返回-1
 操作对象
ObjectOutputStream
 可以将实现了Serializable的接口的对象转成字节写出到流中
ObjectInputStream
 可以从流中读取一个ObjectOutputStream流写出的对象
 打印流
PrintStream 、PrintWriter
 相比普通的OutputStream和Writer增加了print()和println()方法,这两个方法可以输出实参对象的toString()方法返回值
 这两个类还提供自动flush()的功能
 操作内存缓冲数组
ByteArrayInputStream:可以从一个字节数组中读取字节。
ByteArrayOutputStream: 写出到字节数组(内存)中,可以获取写出的内容装入一个字节数组。通常我们用这个流来缓冲数据。
CharArrayReader:可以从一个字符数组中读取字符。
CharArrayWriter:写出字符到字符数组(内存)中,可以获取写出的内容装入一个字符数组。
 管道流
PipedInputStream:管道输入流,可以从管道输出流中读取数据
PipedOutputStream:管道输出流,可以向管道输入流中写出数据
 操作基本数据类型
DataInputStream、DataOutputStream
 可以按照基本数据类型占用空间大小读写数据
 随机访问文件
RandomAccessFile


----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

原创粉丝点击