流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:
(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
(3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件,我们将在下面验证这一点。
优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
字符流类图示:
字节流类图示:
用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
FileReader 用于读取字符流。要读取原始字节流,可以考虑使用 FileInputStream。
/** * 此读入方式由于一次读一个字符,所以效率很低 * 使用字符流读取一个文本文件,将读取到的文本内容打印到控制台。 */ public class Test { public static void main(String[] args) { FileReader fr = null; try { //指定读入流 fr = new FileReader("abc.txt"); int ch = 0; //判断是否读取到文件末尾 while ((ch = fr.read()) != -1) { System.out.println(ch); } } //捕获异常 catch (IOException e) { throw new RuntimeException("读取失败"); } finally { if (fr != null) { try { fr.close(); } catch (IOException e) { System.err.println("关闭失败"); } } } } }
/** * 此读入方式由于每次读入一块而非单个字符,所以效率高 * 使用字符流读取一个文本文件,将读取到的文本内容打印到控制台。 */ public class Test { public static void main(String[] args) { FileReader fr = null; try { //指定读入流 fr = new FileReader("abc.txt"); //指定一个缓冲区 char[] buf = new char[1024]; int len =0; //判断是否读取到文件末尾 while ((len = fr.read(buf)) != -1) { System.out.println(new String(buf, 0, len)); } } //捕获异常 catch (IOException e) { throw new RuntimeException("读取失败"); } finally { if (fr != null) { try { fr.close(); } catch (IOException e) { System.err.println("关闭失败"); } } } } }
用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。
文件是否可用或是否可以被创建取决于底层平台。特别是某些平台一次只允许一个 FileWriter(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
FileWriter 用于写入字符流。要写入原始字节流,可以考虑使用 FileOutputStream。
/** * 在磁盘上写一个文件,并且向文件中写入相应的字母。 * 对IO操作实现异常处理 */ public class Test { public static void main(String[] args) { // 指定一个输出源 FileWriter fw = null; try { fw = new FileWriter("d:\\abc.txt"); // 写入数据 fw.write("abcd"); } catch (IOException e) { // e.printStackTrace(); throw new RuntimeException("写入失败"); } finally { // 刷新并关闭资源 if (fw != null) { try { fw.close(); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("关闭失败"); } } } } }
字符流复制一个文本文件,单个字节写入:
/** * 字符流复制一个文本文件 */ public class Test { public static void main(String[] args) { // 有一个读取源和写入源 FileReader fr = null; FileWriter fw = null; try { fr = new FileReader("d:\\abc.txt"); fw = new FileWriter("d:\\abc_copy.txt"); // 不断读取并且写 int ch = 0; while ((ch = fr.read()) != -1) { fw.write(ch); } } catch (Exception e) { throw new RuntimeException("复制失败"); } finally { // 关闭流 if (fr != null) { try { fr.close(); } catch (IOException e) { System.out.println("关闭失败"); } } if (fw != null) { try { fw.close(); } catch (IOException e) { System.out.println("关闭失败"); } } } } }
文件复制(FileWriter和FileReader结合,字节数组缓冲方法读写):
/** * 字符流复制一个文本文件(高效方法、异常处理)。 */ public class Test { public static void main(String[] args) { // 读取源和写入源 FileReader fr = null; FileWriter fw = null; try { fr = new FileReader("d:\\abc.txt"); fw = new FileWriter("d:\\abc_copy.txt"); // 利用自定义的缓存数组高效读写 char[] buf = new char[1024]; int len = 0; //判断是否读到文件末尾,若没有,则继续 while ((len = fr.read(buf)) != -1) { //一次写入一个缓冲块 fw.write(buf, 0, len); } } catch (Exception e) { throw new RuntimeException("复制失败"); } finally { // 判断读入流对象是否还存在,若存在则关闭 if (fr != null) { try { //关闭读入流 fr.close(); } catch (IOException e) { System.out.println("关闭失败"); } } //判断写出流对象是否还存在,若存在则关闭 if (fw != null) { try { //关闭写出流 fw.close(); } catch (IOException e) { System.out.println("关闭失败"); } } } } }
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如,
BufferedReader in = new BufferedReader(new FileReader("foo.in"));
将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
通过用合适的 BufferedReader 替代每个 DataInputStream,可以对将 DataInputStream 用于文字输入的程序进行本地化。
/** * 高效读取文本数据 */ public class Test { public static void main(String[] args) throws IOException { FileReader fr = null; BufferedReader bfr = null; try { //获取读入源 fr = new FileReader("abc.txt"); bfr = new BufferedReader(fr); String line = null; //循环将数据读入字符数组 while ((line = bfr.readLine()) != null) { System.out.println(line); } } catch (IOException e) { throw new RuntimeException("读取文件失败"); } finally { if (bfr != null) { try { //关闭流 bfr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性 line.separator 定义。并非所有平台都使用新行符 ('\n') 来终止各行。因此调用此方法来终止每个输出行要优于直接写入新行符。
通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。
/** * 字符流 copy文本文件 */ public class Test { private static int BUFFER_SIZE = 1024; public static void main(String[] args) throws IOException { copy_text(); } /* * 指定一个读取源 读取源是文本文件 * 指定一个写入目的 也是一个文件 文件名可以和源读取文件不一样 * 频繁读取文本文件的内容 频繁的写入缓冲区 * 关闭并且刷新内容到目的地 */ public static void copy_text() { FileReader fr = null; FileWriter fw = null; BufferedReader bfr = null; BufferedWriter bfw = null; //定义源 try { //读取源 fr = new FileReader("d:\\abc.txt"); //高效读取 bfr = new BufferedReader(fr); //写入源 fw = new FileWriter("d:\\cc.txt"); //高效写入 bfw = new BufferedWriter(fw); //循环读写文件至末尾 String line = null; while ((line = bfr.readLine()) != null) { bfw.write(line); bfw.newLine(); bfw.flush(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //关闭流 if (bfr != null) { try { bfr.close(); } catch (IOException e) { throw new RuntimeException("关闭失败"); } } if (bfw != null) { try { bfw.close(); } catch (IOException e) { throw new RuntimeException("关闭失败"); } } } } }
FileInputStream 从文件系统中的某个文件中获得输入字节。
FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,可以考虑使用 FileReader。
逐个字节读取文本文件:
/** * 字节流 * 读文件内容,节省空间 */ public class Test { public static void main(String[] args) throws IOException { //创建文件读取的文件对象 String fileName = "abc.txt"; File f = new File(fileName); //获取读入流 InputStream in = new FileInputStream(f); //获取文件字节大小,然后创建字节数组 (不适合过大文件的读取) byte[] b = new byte[(int) f.length()]; //循环读取字节 for (int i = 0; i < b.length; i++) { b[i] = (byte) in.read(); } if(in != null){ try { //关闭读取流对象 in.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println(new String(b)); } }
通过字节流数组缓冲,高效读取文本文件:
/** * 字节流 * 读文件内容,节省空间 */ public class Test { public static void main(String[] args) throws IOException { //创建文件读取的文件对象 String fileName = "abc.txt"; File f = new File(fileName); //获取读入流 InputStream in = new FileInputStream(f); //获取文件字节大小,然后创建字节数组 (不适合过大文件的读取) byte[] buf = new byte[1024]; //循环读取字节 int len = 0; //创建StringBuilder对象,用于连接读取后字符形成的字符串 StringBuilder sb = new StringBuilder(); while ((len = in.read(buf)) != -1) { sb.append(new String(buf, 0, len)); } if (in != null) { try { //关闭读取流对象 in.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println(sb.toString()); } }
文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,可以考虑使用 FileWriter。
逐个字节写出到文件:
public class Test { public static void main(String[] args) throws IOException { //定义写出的文件对象 String fileName ="hello.txt"; File f = new File(fileName); //获取写出流对象 OutputStream out = new FileOutputStream(f); //OutputStream out = new FileOutputStream(f,true); //以追加方式写入文件 String str = "Hello World!!"; //把字符串转成字节数组 byte[] b = str.getBytes(); //逐个字节写出到文件 for (int i = 0; i < b.length; i++) { out.write(b[i]); } //关闭写出流对象 out.close(); } }
通过字节数组写入到文件:
/** * 字节流 * */ import java.io.*; public class Test { public static void main(String[] args) throws IOException { //定义写出的文件对象 String fileName ="hello.txt"; File f = new File(fileName); //获取写出流对象 OutputStream out = new FileOutputStream(f); //OutputStream out = new FileOutputStream(f,true); //以追加方式写入文件 String str = "Hello World!!"; //把字符串转成字节数组 byte[] bytes = str.getBytes(); //通过写出流写出到文件 out.write(bytes); //关闭写出流对象 out.close(); } }
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
/* * 复制图片 */ public class Test { public static void copy_jpg() throws IOException { //定义图片读取源 FileInputStream fis = new FileInputStream("d:\\"); BufferedInputStream bfis = new BufferedInputStream(fis); //定义图片写入源 FileOutputStream fos = new FileOutputStream("d:\\1.mkv"); BufferedOutputStream bfos = new BufferedOutputStream(fos); //使用字节缓冲数组,高效读取 byte[] buf = new byte[1024]; int len = 0; while ((len = bfis.read(buf)) != -1) { bfos.write(buf, 0, len); //不需要这个刷新,查API文档可知这个flush方法中无有效执行代码 //bfos.flush(); } //关闭读入流 bfis.close(); //关闭写出流 bfos.close(); } }
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
/** * 将字节流转换为字符流 */ public class Test { public static void main(String[] args) throws IOException { //控制台输入 InputStream in = System.in; //将字节流转化为字符流 InputStreamReader isr = new InputStreamReader(in); int ch = 0; //循环读取 while ((ch = isr.read()) != -1) { System.out.print((char) ch); } isr.close(); } }
字符编码:
/** * 读取window创建的文件--其中有中文字符 */ public class Test { public static void main(String[] args) throws IOException { //使用字节流读取一个指定的文本文件 FileInputStream fis = new FileInputStream("d:\\b.txt"); //使用转换流将文本文件内容转换为字符流 转换时指定对应的字符集进行读取 InputStreamReader isr = new InputStreamReader(fis, "gbk"); //高效读取 BufferedReader bfr = new BufferedReader(isr); int ch = 0; //循环读取 while ((ch = isr.read()) != -1) { System.out.println((char) ch); } } }
/** * 复制一个文本文件(指定读入写出编码) */ public class Test { public static void main(String[] args) throws IOException { //读取源文件 //转换并指定编码进行读取 //高效读取 BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream("d:\\abc.txt"), "gbk")); //目标文件 //指定编码集进行写入 //高效写入 BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:\\ccc.txt"), "gbk")); //循环读取并且写入目标文件 String line = null; while((line = bfr.readLine()) != null){ bfw.write(line); //写入换行符(由于bfw整行读取,不包括换行符,所以需要自己添加) bfw.newLine(); //刷新缓冲区 bfw.flush(); } //关闭流 bfr.close(); bfw.close(); } }
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
public class Test { public static void main(String[] args) throws IOException { File file = new File("d:" + File.separator + "hello.txt"); //创建读入流对象input DataInputStream input = new DataInputStream(new FileInputStream(file)); char[] ch = new char[10]; int count = 0; char temp; //循环读取 while ((temp = input.readChar()) != 'C') { ch[count++] = temp; } System.out.println(ch); } }
数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
public class Test { public static void main(String[] args) throws IOException { //创建文件对象 File file = new File("d:" + File.separator + "hello.txt"); char[] ch = {'A', 'B', 'C'}; DataOutputStream out = null; //创建读入流对象 out = new DataOutputStream(new FileOutputStream(file)); for (char temp : ch) { //写入字符 out.writeChar(temp); } out.close(); } }
PushbackInputStream 为另一个输入流添加性能,即“推回 (push back)”或“取消读取 (unread)”一个字节的能力。在代码片段可以很方便地读取由特定字节值分隔的不定数量的数据字节时,这很有用;在读取终止字节后,代码片段可以“取消读取”该字节,这样,输入流上的下一个读取操作将会重新读取被推回的字节。例如,表示构成标识符字符的字节可能由表示操作符字符的字节终止;用于读取一个标识符的方法可以读取到遇到操作符为止,然后将该操作符推回以进行重读。
public class Test { public static void main(String[] args) throws IOException { String str = "hello,rollenholt"; PushbackInputStream push = null; ByteArrayInputStream bat = null; //创建ByteArrayInputStream读入流对象 bat = new ByteArrayInputStream(str.getBytes()); //创建PushbackInputStream读入流对象 push = new PushbackInputStream(bat); int temp = 0; while ((temp = push.read()) != -1) { if (temp == ',') { //推回 byte 数组的某一部分:将其复制到推回缓冲区之前。 push.unread(temp); //从此输入流中读取下一个数据字节 temp = push.read(); System.out.print("(回退" + (char) temp + ") "); } else { System.out.print((char) temp); } } } }
管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。
可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态。
/** * 管道流 */ class Test { public static void main(String[] args) throws IOException { //创建发送对象 Send send = new Send(); //创建接收对象 Recive recive = new Recive(); try { //管道连接 send.getOut().connect(recive.getInput()); } catch (Exception e) { e.printStackTrace(); } new Thread(send).start(); new Thread(recive).start(); } } /** * 消息发送类 */ class Send implements Runnable { private PipedOutputStream out = null; //无参构造函数 public Send() { out = new PipedOutputStream(); } //获取管道写出流 public PipedOutputStream getOut() { return this.out; } @Override //重写Runnable接口的run()方法 public void run() { String message = "hello , Alice"; try { out.write(message.getBytes()); } catch (Exception e) { e.printStackTrace(); } try { //关闭写出流 out.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 接受消息类 */ class Recive implements Runnable { private PipedInputStream input = null; //无参构造函数 public Recive() { this.input = new PipedInputStream(); } //获取管道读入流对象 public PipedInputStream getInput() { return this.input; } @Override //重写Runnable接口的run()方法 public void run() { byte[] b = new byte[1000]; int len = 0; try { len = this.input.read(b); } catch (Exception e) { e.printStackTrace(); } try { //关闭读入流对象 input.close(); } catch (Exception e) { e.printStackTrace(); } System.out.println("接受的内容: " + (new String(b, 0, len))); } }
此类为以 ZIP 文件格式写入文件实现输出流过滤器。包括对已压缩和未压缩条目的支持。
/** * 创建压缩文件示例 */ public class Test { public static void main(String[] args) throws IOException { //创建压缩源文件对象 File file = new File("d:" + File.separator + "hello.txt"); //创建压缩文件对象 File zipFile = new File("d:" + File.separator + "hello.zip"); //创建源文件读入流对象 InputStream input = new FileInputStream(file); //创建压缩文件写出流对象 ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream( zipFile)); //开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处 zipOut.putNextEntry(new ZipEntry(file.getName())); // 设置注释 zipOut.setComment("hello"); int temp = 0; //循环写入字节 while ((temp = input.read()) != -1) { zipOut.write(temp); } //关闭读入流 input.close(); //关闭写出流 zipOut.close(); } }
ZipOutputStream类压缩多个文件:
public class Test { public static void main(String[] args) throws IOException { // 要被压缩的文件夹 File file = new File("d:" + File.separator + "temp"); File zipFile = new File("d:" + File.separator + "zipFile.zip"); InputStream input = null; ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream( zipFile)); zipOut.setComment("hello"); if (file.isDirectory()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; ++i) { input = new FileInputStream(files[i]); zipOut.putNextEntry(new ZipEntry(file.getName() + File.separator + files[i].getName())); int temp = 0; while ((temp = input.read()) != -1) { zipOut.write(temp); } input.close(); } } zipOut.close(); } }
ZipInputStream类解压缩(包含多个文件的情况):
/** * 解压缩一个压缩文件中包含多个文件的情况 */ public class Test { public static void main(String[] args) throws IOException { File file = new File("d:" + File.separator + "zipFile.zip"); File outFile = null; ZipFile zipFile = new ZipFile(file); ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file)); ZipEntry entry = null; InputStream input = null; OutputStream output = null; while ((entry = zipInput.getNextEntry()) != null) { System.out.println("解压缩" + entry.getName() + "文件"); outFile = new File("d:" + File.separator + entry.getName()); if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdir(); } if (!outFile.exists()) { outFile.createNewFile(); } input = zipFile.getInputStream(entry); output = new FileOutputStream(outFile); int temp = 0; while ((temp = input.read()) != -1) { output.write(temp); } input.close(); output.close(); } } }
SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
/** * 文件合并 */ public class Test { public static void main(String[] args) throws IOException { //定义输出 FileOutputStream fos = new FileOutputStream("d:\\aaa\\d.txt"); //将一组流添加到list中 ArrayList<FileInputStream> al = new ArrayList<FileInputStream>(); al.add(new FileInputStream("d:\\aaa\\a.txt")); al.add(new FileInputStream("d:\\aaa\\b.txt")); al.add(new FileInputStream("d:\\aaa\\c.txt")); //将list转换为Enumeration Enumeration<FileInputStream> en = Collections.enumeration(al); //创建序列流读入对象 SequenceInputStream sis = new SequenceInputStream(en); //创建缓冲字节数组 byte[] buf = new byte[1024]; int len = 0; //循环读取字节数据 while ((len = sis.read(buf)) != -1) { fos.write(buf, 0, len); } //关闭流 sis.close(); fos.close(); } }
/** * 文件切割 */ public class Test { public static void main(String[] args) throws IOException { splitFile(); } public static void splitFile() throws IOException { /* * 有一个较大源读取文件 * 创建读取的文件对象 */ File file = new File("d:\\aaa\\y.rmvb"); //创建读入流对象 FileInputStream fis = new FileInputStream(file); //创建写出流对象 FileOutputStream fos = null; //切割文件大小 byte[] buf = new byte[1024 * 1024 * 10]; int count = 0; int len = 0; //循环切割 while ((len = fis.read(buf)) != -1) { count++; //创建写出流 fos = new FileOutputStream(new File(file.getParent() + "\\" + count + ".part")); //写出数据 fos.write(buf, 0, len); //关闭写出流 fos.close(); } //关闭读入流 fis.close(); } }
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
public class Test { public static void main(String[] args) throws IOException { //创建读入写出流对象 FileOutputStream outputStream = new FileOutputStream("hello.obj"); FileInputStream inputStream = new FileInputStream("hello.obj"); //创建对象读入写出流对象 ObjectOutputStream objOut = new ObjectOutputStream(outputStream); ObjectInputStream objIn = new ObjectInputStream(inputStream); //创建一个Person对象 Person person = new Person("Alice", 20); //把person对象写入对象流中 objOut.writeObject(person); //读入person对象 Person object = null; try { object = (Person) objIn.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(person.getName() + " : " + person.getAge()); } } //定义Person类,要想实现序列化,必须实现Serializable接口 class Person implements Serializable { //显示指定serialVersionUID,防止由于JDK版本不对而出现序列化操作失败的问题 private static final long serialVersionUID = 1L; private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } 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; } }
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
Properties配置文件:
/** * Properties配置存储为文件 */ public class Test { public static void main(String[] args) throws IOException{ Properties prop = new Properties(); prop.setProperty("zhangsan", "15000"); prop.setProperty("lisi", "8000"); prop.setProperty("wangwu", "20000"); //prop.list(System.out);//测试用 prop.store(new FileOutputStream("a.properties"), "configuration"); prop.setProperty("wangwu", "10000"); System.out.println(prop.getProperty("wangwu")); } }
/** * Properties */ public class Test { public static void main(String[] args) throws IOException { //获取系统配置信息 Properties properties = System.getProperties(); System.out.println(properties.toString()); //将配置信息打印到控制台 //list方法经常用来调试,当前配置中的所有配置 properties.list(System.out); //设置配置信息(自定义的配置) Properties prop = new Properties(); prop.setProperty("zhangsan", "15000"); prop.setProperty("lisi", "18000"); prop.setProperty("wangwu", "8000"); prop.list(System.out); String s = prop.getProperty("lisi"); System.out.println(s); //获取全部配置信息(使用集合遍历) Set<String> props = prop.stringPropertyNames(); for (String key : props) { System.out.println(key + " -> " + prop.getProperty(key)); } //读取配置文件中的配置信息 Properties prop2 = new Properties(); //把配置信息输出到文件 FileInputStream is =new FileInputStream("salary.properties"); //加载文件中的配置信息到prop2中 prop2.load(is); String ss = prop2.getProperty("zhangsan"); System.out.println(ss); //控制台打印 prop2.list(System.out); } }
/** * File类的用法 */ public class Test { public static void main(String[] args) { //实例化对象时,文件不会产生 //File(String pathname) File file = new File("d:\\abc.txt"); File file1 = new File("d:\\"); //同一个分区的多个文件操作 多个分区的同一个文件 // File(String parent, String child) File file2 = new File("d:\\","abc.txt"); // File(File parent, String child) File path = new File("d:\\"); File file3 = new File(path,"abc.txt"); System.out.println(File.separator); // System.getProperty("file.separator") System.out.println(File.separatorChar); // System.getProperty("file.separator") System.out.println(System.getProperty("file.separator")); System.out.println(File.pathSeparator); // } }
/** * 打印一个文件的所有属性 */ public class Test { public static void main(String[] args) throws IOException { File file = new File("d:\\cd.txt"); System.out.println("getAbsolutePath = " + file.getAbsolutePath()); //绝对路径 System.out.println("getName=" + file.getName()); //文件名 System.out.println("getCanonicalPath=" + file.getCanonicalPath()); //绝对路径的规范形式 System.out.println("getPath=" + file.getPath()); //定义文件路径时 内容是什么就打印什么 System.out.println("length=" + file.length()); //文件大小 System.out.println("lastModified=" + file.lastModified()); //最后修改时间 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); long t = file.lastModified(); String time = sdf.format(t); System.out.println(time); } }
/** * 文件合并、文件分割、配置文件使用 */ public class Test { public static void main(String[] args) throws IOException { //指定需要切割的文件 File filein = new File("D:\\aaa\\y.rmvb"); //指定合并后的目录 File fileout = new File("D:\\bbb"); //切分 //split_file(filein); //合并 merge_file(new File(filein.getParent()), fileout); } /** * 合并文件 * * @param fileout :合并后的目录 * @param filein :合并前的目录 * @throws IOException */ public static void merge_file(File filein, File fileout) throws IOException { /* 获取配置文件信息*/ Properties prop = new Properties(); File[] propFiles = filein.listFiles(new MyFilenameFilter(".properties")); /*校验部分*/ if (propFiles.length != 1) { //此地默认切分生成目录中只有一个配置文件 如果有多个配置文件 不予合并 throw new RuntimeException("配置文件不存在或者不唯一"); } //将取到的唯一的配置文件加载到Properties对象中 prop.load(new FileInputStream(propFiles[0])); //遍历并查找文件切分后的文件 File[] listFiles = filein.listFiles(new MyFilenameFilter(".part")); //判断文件个数是否等于切分时写入配置文件中的个数 if (listFiles.length != Integer.parseInt(prop.getProperty("filesplitnum"))) { throw new RuntimeException("文件缺失!"); } /*合并部分*/ //最终输出的文件名 从配置文件中读取 合并到fileout中 FileOutputStream fos = new FileOutputStream(new File(fileout, prop.getProperty("filename"))); //定义一个容器 ArrayList<FileInputStream> al = new ArrayList<FileInputStream>(); for (File file : listFiles) { al.add(new FileInputStream(file)); } //将ArrayList中转换为Enumeration Enumeration<FileInputStream> en = Collections.enumeration(al); //使用序列流合并 SequenceInputStream sis = new SequenceInputStream(en); //开始合并 byte[] buf = new byte[1024]; int len = 0; while ((len = sis.read(buf)) != -1) { fos.write(buf, 0, len); } /* 资源释放部分*/ //关闭流 sis.close(); fos.close(); }
/** * 切割文件 * 参数一 file: 传递进来需要切割的文件 * * @throws IOException */ public static void split_file(File file) throws IOException { //读取原来的大文件 FileInputStream fis = new FileInputStream(file); //定义输出流 FileOutputStream fos = null; //获取需要切割的文件的所在路径 并将路径封装成为一个File对象 File path = new File(file.getParent()); byte[] buf = new byte[1024*1024 * 30]; int len = 0; int count = 0; while ((len = fis.read(buf)) != -1) { fos = new FileOutputStream(new File(path, (count++) + ".part")); fos.write(buf, 0, len); fos.close(); } //写配置文件 Properties prop = new Properties(); prop.setProperty("filename", file.getName()); prop.setProperty("filesplitnum", count + ""); //将配置对象存储到配置文件中 prop.store(new FileOutputStream(new File(path, file.getName() + ".properties")), "file split infos"); //关闭流 fis.close(); } }
FilenameFilter:
FileFilter 是一个抽象类,JFileChooser 使用它过滤显示给用户的文件集合
FilenameFilter:
实现此接口的类实例可用于过滤器文件名。Abstract Window Toolkit 的文件对话框组件使用这些实例过滤 File 类的 list 方法中的目录清单。
public class Test { public static void main(String[] args) { File file = new File("d:\\abc"); //通过过滤器过滤文件和目录,返回抽象路径名数组 String[] names = file.list(new MyFilenameFilter("d")); //遍历这些路径名字符串 for (String name : names) { System.out.println(name); } } } //实现自己的过滤器 public class MyFilenameFilter implements FilenameFilter { private String suffix; MyFilenameFilter(String suffix) { this.suffix = suffix; } @Override //重写父类accept方法,实现自己的过滤器 public boolean accept(File dir, String name) { return name.endsWith(suffix); } }
/** * 找出指定文件夹下的隐藏文件 和 指定文件扩展名文件 */ public class Test { public static void main(String[] args) { File file = new File("F:\\电影"); // 返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 File[] listFiles = file.listFiles(new MyFileFilter(".mkv")); //遍历这些文件对象 for (File f : listFiles) { System.out.println(f); } } } //自己的构造器类 class MyFileFilter implements FileFilter{ /* * 要隐藏文件 要指定扩展名 */ private String suffix; MyFileFilter(String suffix){ this.suffix = suffix; } @Override //重写父类的accept方法,实现自己的业务逻辑 public boolean accept(File pathname) { return pathname.getName().endsWith(suffix) && !pathname.isHidden(); } }
/** * 深度遍历文件夹 */ public class Test { public static void main(String[] args) { File file = new File("D:\\a"); listAll_3(file, 0); } //添加目录缩进 public static void listAll_3(File file, int count) { System.out.println(addSpace(count) + file); //每调用一次加一次 count++; File[] listFiles = file.listFiles(); for (int i = 0; i < listFiles.length; i++) { //如果是目录 if (listFiles[i].isDirectory()) { listAll_3(listFiles[i], count); } else {//是文件 System.out.println(addSpace(count) + listFiles[i]); } } } //在文件夹前面添加空格 public static String addSpace(int count) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < count; i++) { sb.append("\t"); } return sb.toString(); }
/** * 列出目录中文件 */ public class Test { public static void main(String[] args) { File file = new File("D:\\abc"); //返回文件对象的目录下所有文件名称的字符串 String[] list = file.list(); //遍历这些文件名称字符串 for (String name : list) { //筛选出以.java结尾的文件 if (name.endsWith(".java")) { System.out.println(name); } } } }
/** * 获取指定目录下,指定扩展名的文件(包含子目录中的),将获取到的文件绝对路径按照关键词过滤,存储到UTF-8格式文本文件中。 */ public class Test { public static void main(String[] args) { //需要查找的路径 File path = new File("D:\\a"); File outpath = new File("D:\\aa.txt"); //定义一个容器 List<String> list = new ArrayList<String>(); //定义一个文件名过滤器 MyFilenameFilter filter = new MyFilenameFilter(".txt"); //查找 findFiles(path, list, filter); //关键词 String suffix = "a"; //写结果集 writeFiles(list, outpath, suffix); } /** * 写结果集 * * @param list 结果集 * @param outpath 输出目录 * @param suffix 关键词 */ public static void writeFiles(List<String> list, File outpath, String suffix) { if (list.size() == 0) { return; } BufferedWriter bfw = null; try { //指定写入路径 bfw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outpath), "utf-8")); //遍历结果集 写 for (String path : list) { if (path.contains(suffix)) { bfw.write(path); bfw.newLine(); bfw.flush(); } } } catch (IOException e) { throw new RuntimeException("写入失败 error :" + e.toString()); } finally { //关闭流 if (bfw != null) { try { bfw.close(); } catch (IOException e) { e.printStackTrace(); } } } } /* * 找到符合条件的文件名 * args:path为传递进来文件夹路径 * */ public static void findFiles(File path, List<String> list, MyFilenameFilter filter) { //判断传递进来的路径是否存在 if (!path.exists()) { return; } //根据条件进行过滤 File[] rsList = path.listFiles(); //目录下所有的内容查找出来 if (rsList.length > 0) { //遍历 for (File file : rsList) { if (file.isDirectory()) {//是目录 //递归 findFiles(file, list, filter); } else { //过滤文件扩展名 if (filter.accept(file, file.getName())) { list.add(file.getAbsolutePath()); } } } } } }
/** * 递归删除文件夹 */ public class Test { public static void main(String[] args) { File file = new File("D:\\aa"); deletedir(file); } public static void deletedir(File file) { //列出;路径下的文件及文件夹 File[] listFiles = file.listFiles(); //遍历删除 for(int i = 0 ; i < listFiles.length ; i++){ if(listFiles[i].isDirectory()){//如果是目录 deletedir(listFiles[i]); listFiles[i].delete(); }else{ //不管是目录或者是文件都尝试删一下 listFiles[i].delete(); } } //删除顶级文件夹 file.delete(); } }
/** * 实现创建并删除文件夹或者一个文件 */ public class Test { public static void main(String[] args) throws IOException { File file = new File("D:\\bbb.txt"); //文件创建 //创建一个新的文件 如果文件存在 不创建 boolean b = file.createNewFile(); //虚拟机退出时删除文件 file.deleteOnExit(); //创建不存在的一级目录 boolean b1 = file.mkdir(); //创建不存在的多级目录 boolean b2 = file.mkdirs(); //删除文件或文件夹,当文件夹非空,会出问题 boolean b3 = file.delete(); System.out.println(b); } }
System.in:
/** * 读取键盘输入的数据 打印到控制台上 */ public class Test { public static void main(String[] args) throws IOException { //获取键盘输入的数据 InputStream in = System.in; int ch = 0; //循环读取输入的数据直到末尾 while ((ch = in.read()) != -1) { //将读取的字节流显示转化为字符 System.out.print((char) ch); } } }
System.out:
/** * 实现一个打印程序 */ public class Test { public static void main(String[] args) throws IOException { OutputStream out = System.out; out.write("abcd".getBytes()); } }
/** * 将用户输入的数据写入到文本文件中 */ public class Test { public static void main(String[] args) throws IOException { //输出目的源 FileOutputStream fos = new FileOutputStream("d:\\a.txt"); BufferedOutputStream bfos = new BufferedOutputStream(fos); //获取用户终端输入的数据 InputStream in = System.in; //使用高效读取 BufferedInputStream bin = new BufferedInputStream(in); int ch = 0; //循环读取字节 while ((ch = bin.read()) != -1) { bfos.write(ch); //刷新缓冲区 bfos.flush(); } } }
/** * 将文本文件中的内容打印到控制台上 */ public class Test { public static void main(String[] args)throws IOException { //读取源 FileInputStream fis =new FileInputStream("d:\\a.txt"); OutputStream out = System.out; int ch = 0; while ((ch = fis.read()) != -1) { out.write(ch); } fis.close(); } }
/** * 使用转换流实现输入字符转大写的打印功能 */ public class Test { public static void main(String[] args)throws IOException { read_console(); } public static void read_console()throws IOException { InputStream in = System.in; // 字节流转换为字符流 InputStreamReader isr =new InputStreamReader(in); BufferedReader bfr = new BufferedReader(isr); String line = null; while ((line = bfr.readLine()) !=null) { if ("exit".equals(line)) { return; } System.out.println(line.toUpperCase()); } isr.close(); bfr.close(); } }