流(Stream)

Java 8 API添加了一个新的抽象称为流Stream,可以以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

以上的流程转换为 Java 代码为:

List<Integer> transactionsIds = 
widgets.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();

Stream是一个来自数据源的元素队列并支持聚合操作:

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算
  • 数据源流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

Stream操作有两个基础的特征

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行laziness和短路short-circuiting
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式Visitor实现。

生成流

在 Java 8 中, 集合接口有两个方法来生成流:

  • stream() 为集合创建串行流,同一时间只有一个流。
  • parallelStream() 为集合创建并行流,同一时间多个流并行。
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

操作流

  • map

    map 方法用于映射每个元素到对应的结果。

    List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
    // 获取对应的平方数
    List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
    
  • filter

    filter 方法用于通过设置的条件过滤出元素。

    List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    // 获取空字符串的数量
    long count = strings.stream().filter(string -> string.isEmpty()).count();
    
  • limit

    limit 方法用于获取指定数量的流。

    Random random = new Random();
    random.ints().limit(10).forEach(System.out::println);
    
  • skip

    skip 方法用于跳过指定数量的流。

    Random random = new Random();
    random.ints().limit(10).skip(3).forEach(System.out::println);
    
  • distinct

    distinct 方法用于去除流中的重复数据。

    List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
    // 获取对应的平方数
    List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
    
  • sorted

    sorted 方法用于对流进行排序。

    Random random = new Random();
    random.ints().limit(10).sorted().forEach(System.out::println);
    
  • 并行parallel程序

    parallelStream 是流并行处理程序的代替方法。

    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    // 获取空字符串的数量
    long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
    

中止流

  • forEach

    Stream 提供了新的方法 forEach 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:

    Random random = new Random();
    random.ints().limit(10).forEach(System.out::println);
    
  • Collectors

    Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

    List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
    
    System.out.println("筛选列表: " + filtered);
    String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
    System.out.println("合并字符串: " + mergedString);
    
  • 统计

    一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。

    List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
    
    IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
    
    System.out.println("列表中最大的数 : " + stats.getMax());
    System.out.println("列表中最小的数 : " + stats.getMin());
    System.out.println("所有数之和 : " + stats.getSum());
    System.out.println("平均数 : " + stats.getAverage());
    

完整案例

public class Java8Tester {
   public static void main(String args[]){
      System.out.println("使用 Java 7: ");
        
      // 计算空字符串
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
      System.out.println("列表: " +strings);
      long count = getCountEmptyStringUsingJava7(strings);
        
      System.out.println("空字符数量为: " + count);
      count = getCountLength3UsingJava7(strings);
        
      System.out.println("字符串长度为 3 的数量为: " + count);
        
      // 删除空字符串
      List<String> filtered = deleteEmptyStringsUsingJava7(strings);
      System.out.println("筛选后的列表: " + filtered);
        
      // 删除空字符串,并使用逗号把它们合并起来
      String mergedString = getMergedStringUsingJava7(strings,", ");
      System.out.println("合并字符串: " + mergedString);
      List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        
      // 获取列表元素平方数
      List<Integer> squaresList = getSquares(numbers);
      System.out.println("平方数列表: " + squaresList);
      List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
        
      System.out.println("列表: " +integers);
      System.out.println("列表中最大的数 : " + getMax(integers));
      System.out.println("列表中最小的数 : " + getMin(integers));
      System.out.println("所有数之和 : " + getSum(integers));
      System.out.println("平均数 : " + getAverage(integers));
      System.out.println("随机数: ");
        
      // 输出10个随机数
      Random random = new Random();
        
      for(int i=0; i < 10; i++){
         System.out.println(random.nextInt());
      }
        
      System.out.println("使用 Java 8: ");
      System.out.println("列表: " +strings);
        
      count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("空字符串数量为: " + count);
        
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("字符串长度为 3 的数量为: " + count);
        
      filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
      System.out.println("筛选后的列表: " + filtered);
        
      mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
      System.out.println("合并字符串: " + mergedString);
        
      squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
      System.out.println("Squares List: " + squaresList);
      System.out.println("列表: " +integers);
        
      IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
        
      System.out.println("列表中最大的数 : " + stats.getMax());
      System.out.println("列表中最小的数 : " + stats.getMin());
      System.out.println("所有数之和 : " + stats.getSum());
      System.out.println("平均数 : " + stats.getAverage());
      System.out.println("随机数: ");
        
      random.ints().limit(10).sorted().forEach(System.out::println);
        
      // 并行处理
      count = strings.parallelStream().filter(string -> string.isEmpty()).count();
      System.out.println("空字符串的数量为: " + count);
   }
    
   private static int getCountEmptyStringUsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.isEmpty()){
            count++;
         }
      }
      return count;
   }
    
   private static int getCountLength3UsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.length() == 3){
            count++;
         }
      }
      return count;
   }
    
   private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
      List<String> filteredList = new ArrayList<String>();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
             filteredList.add(string);
         }
      }
      return filteredList;
   }
    
   private static String getMergedStringUsingJava7(List<String> strings, String separator){
      StringBuilder stringBuilder = new StringBuilder();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
            stringBuilder.append(string);
            stringBuilder.append(separator);
         }
      }
      String mergedString = stringBuilder.toString();
      return mergedString.substring(0, mergedString.length()-2);
   }
    
   private static List<Integer> getSquares(List<Integer> numbers){
      List<Integer> squaresList = new ArrayList<Integer>();
        
      for(Integer number: numbers){
         Integer square = new Integer(number.intValue() * number.intValue());
            
         if(!squaresList.contains(square)){
            squaresList.add(square);
         }
      }
      return squaresList;
   }
    
   private static int getMax(List<Integer> numbers){
      int max = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
        
         Integer number = numbers.get(i);
            
         if(number.intValue() > max){
            max = number.intValue();
         }
      }
      return max;
   }
    
   private static int getMin(List<Integer> numbers){
      int min = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
         Integer number = numbers.get(i);
        
         if(number.intValue() < min){
            min = number.intValue();
         }
      }
      return min;
   }
    
   private static int getSum(List numbers){
      int sum = (int)(numbers.get(0));
        
      for(int i=1;i < numbers.size();i++){
         sum += (int)numbers.get(i);
      }
      return sum;
   }
    
   private static int getAverage(List<Integer> numbers){
      return getSum(numbers) / numbers.size();
   }
}

文件(File)

计算机文件是以计算机硬盘为载体存储在计算机上的信息集合,对于计算机磁盘的文件和目录,Java提供了对应的一个类File来描述。

构造方法File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。

File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。

File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。

常用方法

方法 描述
String getName() 返回由此抽象路径名表示的文件或目录的名称。
String getParent() 返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null。
File getParentFile() 返回此抽象路径名的父路径名的抽象路径名,如果此路径名没有指定父目录,则返回 null。
String getPath() 将此抽象路径名转换为一个路径名字符串。
boolean isAbsolute() 测试此抽象路径名是否为绝对路径名。
String getAbsolutePath() 返回抽象路径名的绝对路径名字符串。
boolean canRead() 测试应用程序是否可以读取此抽象路径名表示的文件。
boolean canWrite() 测试应用程序是否可以修改此抽象路径名表示的文件。
boolean exists() 测试此抽象路径名表示的文件或目录是否存在。
boolean isDirectory() 测试此抽象路径名表示的文件是否是一个目录。
boolean isFile() 测试此抽象路径名表示的文件是否是一个标准文件。
long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
long length() 返回由此抽象路径名表示的文件的长度。
boolean createNewFile() 当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。
boolean delete() 删除此抽象路径名表示的文件或目录。
void deleteOnExit() 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。
String[] list() 返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。
String[] list(FilenameFilter filter) 返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。
File[] listFiles() 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。
File[] listFiles(FileFilter filter) 返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。
boolean mkdir() 创建此抽象路径名指定的目录。
boolean mkdirs() 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。
boolean renameTo(File dest) 重新命名此抽象路径名表示的文件。
boolean setLastModified(long time) 设置由此抽象路径名所指定的文件或目录的最后一次修改时间。
boolean setReadOnly() 标记此抽象路径名指定的文件或目录,以便只可对其进行读操作。
static File createTempFile(String prefix, String suffix, File directory) 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。
static File createTempFile(String prefix, String suffix) 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。
int compareTo(File pathname) 按字母顺序比较两个抽象路径名。
int compareTo(Object o) 按字母顺序比较抽象路径名与给定对象。
boolean equals(Object obj) 测试此抽象路径名与给定对象是否相等。
String toString() 返回此抽象路径名的路径名字符串。
// boolean mkdir() 创建由此抽象路径名命名的目录。
File f1 = new File("C:\\Users\\admin\\Desktop\\2");
if (!f1.exists()) { // 目录不存在
	f1.mkdir();
}
File f2 = new File("C:\\Users\\admin\\Desktop\\2\\22\\222");
System.out.println(f2.exists());
f2.mkdir(); // 注意:mkdir()上一级目录存在,不然创建失败

// boolean mkdirs () 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
File f3 = new File("C:\\Users\\admin\\Desktop\\2\\22\\222");
f3.mkdirs();

// boolean createNewFile ()当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
File f4 = new File("C:\\Users\\admin\\Desktop\\2\\2.avi");
f4.createNewFile();

文件过滤器

Java提供文件过滤器接口有两种FileFilterFilenameFilter,两个接口均无实现类,因此需要自定义实现过滤器接口来定义过滤器类。

  • FileFilter用于抽象路径名(File对象)的过滤器。

    boolean accept(File pathname)用来过滤文件的方法,测试指定抽象路径名是否应该包含在某个路径名列表中。

    其中File pathname使用ListFiles方法遍历目录,得到的每一个文件对象

  • FilenameFilter实现此接口的类实例可用于过滤器文件名

    boolean accept(File dir, String name) 用来过滤文件的方法,测试指定文件是否应该包含在某一文件列表中。

    其中File dir构造方法中传递的被遍历的目录;String name使用ListFiles方法遍历目录,获取的每一个文件/文件夹的名称

public class FileFilterTest {
	
	public static void main(String[] args) {
		File file = new File("./");
		// 列出目录下的所有文件和文件夹
		String[] files = file.list();
		for(int i = 0; i < files.length; i++) {
			 System.out.println(files[i]);
		}
		
		// 分别用FilenameFilter 和 FileFilter 实现过滤以.txt为后缀的文件
		String[] files1 = file.list(new MyFilenameFilter(".txt"));
		for(int i = 0; i < files1.length; i++) {
			 System.out.println(files1[i]);
		}
		
		// MyFileFilter过滤器用于 listFiles 函数
		File[] files2 = file.listFiles(new MyFileFilter(".txt"));
		for(int i = 0; i < files2.length; i++) {
			System.out.println(files2[i].getName());
		}
	}
}
 
class MyFilenameFilter implements FilenameFilter {
	// type为需要过滤的条件,比如如果type=".jpg",则只能返回后缀为jpg的文件
	private String type;
 
	public MyFilenameFilter(String type) {
		this.type = type;
	}
	
	@Override
	// 返回true的文件则合格
	public boolean accept(File dir, String name) {
		// 这里如果需要使用文件的功能,则需要先进行封装
		File file = new File(dir,name);
		
		return name.endsWith(type) && file.isFile();
	}
}
 
class MyFileFilter implements FileFilter {
	private String type;
 
	public MyFileFilter(String type) {
		this.type = type;
	}
	
	@Override
	public boolean accept(File pathname) {
		// 这里如果需要使用文件的功能直接使用即可
		return pathname.getName().endsWith(type) && pathname.isFile();
	}
}

FileFilterFilenameFilter 的区别

FilenameFilter过滤器中的accept方法接受两个参数,一个当前文件夹,一个是当前文件夹子对象的名称。

FileFilter 过滤器中的accept方法接受一个参数,这个参数是当前文件夹的子对象。

当需要过滤文件或目录名称时就可以使用FilenameFilter这个过滤器,当对当前文件或文件夹进行过滤,就可以使用FileFilter ,比如需要当前目录下的所有文件夹,就可以使用 FileFilter 过滤器。

IO

I/O 即输入Input/ 输出Output的缩写,其实就是计算机调度把各个存储中(包括内存和外部存储)的数据写入写出的过程;java中用流(stream)来抽象表示这么一个写入写出的功能,封装成一个“类”,都放在java.io这个包里面。

IO流的分类

输入流和输出流的类层次图

  • 按照流的方向划分(输出输入都是站在程序所在内存的角度划分的)

    输入流:只能从中读取数据(主要由InputStreamReader作为基类)

    输出流:只能向其写入数据(主要由outputStreamWriter作为基类)

    从磁盘读取数据到内存是输入流,从client读取数据到server是输入流;同样,把内存数据写到磁盘是输出流,把server数据写到client是输出流

  • 按照流的操作颗粒度划分

    字节流:以字节为单元,可操作任何数据(主要由InputStreamoutPutStream作为基类)

    字符流:以字符为单元,只能操作纯字符数据,比较方便(主要由ReaderWriter作为基类)

  • 按照流的角色划分

    节点流:可以从/向一个特定的IO设备(如磁盘,网络)读/写数据的流,也叫低级流主要流

    处理流:用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能,也叫高级流

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
文件 FileInputStream FileOutputStream FileReader FileWrite
数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
管道 PipedInputstream PipedOutputStream PipedReader PipedWriter
字符串 StringReader StringWriter
缓冲流 BufferedlnputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream
抽象基类 FilterInputStream FilterOutputStream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输出流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

访问操作文件

访问操作文件分为四个部分:FileInputStream/FileReaderFileOutputStream/FileWriter

FileInputStream

构造方法

  1. FileInputStream(File file) 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的 File对象 file命名。
  2. FileInputStream(String name) 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的路径名 name命名。
  3. FileInputStream(FileDescriptor fdObj)使用文件描述符 fdObj创建 FileInputStream ,该文件描述符表示与文件系统中实际文件的现有连接。

常用方法

方法 描述
available() 返回可以从此输入流中读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
close() 关闭此文件输入流并释放与该流关联的所有系统资源。
read() 从此输入流中读取一个字节的数据。
read(byte[] b) 从此输入流 b.length最多 b.length字节的数据读 b.length字节数组。
read(byte[] b, int off, int len) 从此输入流 len最多 len字节的数据读入一个字节数组。
skip(long n) 跳过并从输入流中丢弃 n字节的数据。
public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("/1.txt");

        FileInputStream fis1 = new FileInputStream(f);
        int len1 = -1;
        byte[] buffer1 = new byte[1024];
        while ((len1 = fis1.read(buffer1)) != -1){
            System.out.print(new String(buffer1,0,len1));
        }

        System.out.println();
        FileInputStream fis2 = new FileInputStream(f);
        int len2 = -1;
        byte[] buffer2 = new byte[1024];
        while ((len2 = fis2.read(buffer2,1,3)) != -1){
            System.out.print(new String(buffer2,2,len2 - 1));
        }

        fis2.close();
        fis1.close();
    }
}

FileOutputStream

构造方法

  1. FileOutputStream(File file)创建文件输出流以写入由指定的 File对象表示的文件。

  2. FileOutputStream(File file, boolean append)创建文件输出流以写入由指定的 File对象表示的文件;appendtrue表示追加,为false表示覆盖。

  3. FileOutputStream(String name)创建文件输出流以写入具有指定名称的文件。

  4. FileOutputStream(String name, boolean append)创建文件输出流以写入具有指定名称的文件;appendtrue表示追加,为false表示覆盖。

常用方法

方法 描述
close() 关闭此文件输出流并释放与此流关联的所有系统资源。
write(byte[] b) 将指定字节数组中的 b.length字节写入此文件输出流。
write(byte[] b, int off, int len) 将从偏移量 off开始的指定字节数组中的 len字节写入此文件输出流。
write(int b) 将指定的字节写入此文件输出流。
public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("/1.txt");
        FileOutputStream fos = new FileOutputStream(f);
        byte[] buffer = {'B','r','u','i','s','e','s','L'};
        fos.write(buffer, 0, buffer.length);
    }
}
public class CopyDemo {
    public static void main(String[] args) throws IOException {
        File f1 = new File("/1.txt");
        File f2 = new File("/2.txt");

        FileInputStream fis = new FileInputStream(f1);
        FileOutputStream fos = new FileOutputStream(f2);

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

缓存流的使用

如果循环独写数据,操作磁盘的次数非常多,影响性能,通过缓存流,可以先缓存大量读写数据,等到比较多了之后,在连接磁盘一次从磁盘读取或者写,避免多次连接磁盘影响性能。

缓存流有:BufferedInputStream/BufferedOutputStreamBufferedReader/BufferedWriter

public class TestBufferStream {
	public static void main (String[] args) throws IOException{
		BufferedInputStream bis=null;
		BufferedOutputStream bos=null;
		try {
			FileInputStream fis = new FileInputStream("/TestFileImportStream.java");
			FileOutputStream fos = new FileOutputStream("/out2.java");
			bis = new BufferedInputStream(fis); // 加了缓存的功能流BufferedInputStream
			bos = new BufferedOutputStream(fos);// 加了缓存的功能流BufferedOutputStream
			byte[] b = new byte[1024];
			int off=0;
			while ((off=bis.read(b))>0) {
				bos.write(b,0,off);
			}
			bis.close();
			bos.close();
		}catch (IOException e) {
			e.printStackTrace();
		}finally {
			bis.close();
			bos.close();
		}		
	}
}
// 为文件字节流 添加缓冲区功能, 一次读写一个字节数据,但内部缓冲区数组已经填满
private static void copyFile1(String src, String dest) throws IOException {
    // 创建流
    InputStream in = new BufferedInputStream(new FileInputStream(src));
    OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
    // 读写数据
    int data = in.read();
    while (data != -1) {
        os.write(data);
        data = in.read();
    }
    // 关闭流
    in.close();
    os.close();
}

// 为文件字节流 添加缓冲区功能, 一次读写一个字节数组数据,但内部缓冲区数组已经填满
private static void copyFile2(String src, String dest) throws IOException {
    // 创建流
    InputStream in = new BufferedInputStream(new FileInputStream(src));
    OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));

    // 读写数据
    byte[] buffer = new byte[2048];
    int len = in.read(buffer);
    while (len != -1) {
        os.write(buffer, 0, len);
        len = in.read(buffer);
    }
    // 关闭流
    in.close();
    os.close();
}
public class TransStreamTest {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new FileWriter("/1.txt"));
		String line =null;
    // readLine()方法在进行读取一行时,只有遇到回车(\r)或者换行符(\n)才会返回读取结果
		while ((line=br.readLine())!=null) {
			if ("over".contentEquals(line)) {
				break;
			}
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
    bw.close();
    br.close();
	}

}

转换流的使用

转换流有:InputStreamReader/OutputStreamWriter

InputStreamReader

InputStreamReader 拓展至 Reader,是一种特殊的Reader,将从文件读取的字节流转换为字符流。

构造方法

  1. InputStreamReader(InputStream in)

  2. InputStreamReader(InputStream in, Charset cs)

  3. InputStreamReader(InputStream in, String charsetName)

InputStream is = new FileInputStream("/1.txt");
InputStreamReader r = new InputStreamReader (is);
char[] cbuf = new char[10];
int len;
while((len = r.read(cbuf))!=-1){
	System.out.println(new String(cbuf,0,len));
}
r.close();

OutputStreamReader

OutputStreamReader 拓展至 Writer,是一种特殊的Writer,将内存加载的字节流转换为字符流。

构造方法

  1. OutputStreamWriter(OutputStream out)

  2. OutputStreamWriter(OutputStream out, Charset cs)

  3. OutputStreamWriter(OutputStream out, String charsetName)

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("/1.txt"));
osw.write("罗新驰");
osw.close();

对象流的使用

对象流(ObjectOutputStream)其实就是一种特殊的处理流水,也是在基础的字节流上去作封装。

public class ObjectStreamTest {
	public static void main(String[] args) throws Exception{
		try {
			Person P=new Person("Jeccica",26);
			FileOutputStream fos=new FileOutputStream("/1.txt");
			ObjectOutputStream oos=new ObjectOutputStream(fos);
			oos.writeObject(P);
			oos.flush();
			oos.close();
		}catch(FileNotFoundException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}			
		
		FileInputStream fis=new FileInputStream("/1.txt");
		ObjectInputStream ois=new ObjectInputStream(fis);
		Person P2=(Person)ois.readObject();
		System.out.println(P2.name+"的年龄为"+P2.age);
	}

}

class Person implements Serializable{
	String name=null;
	int age=0;
	Person(String _name,int _age){
		name=_name;
		age=_age;
	}
}

字节数组流的使用

分析了常见的节点流和常见的处理流等,都是针对文件的操作,然后带上缓冲的节点流进行处理,但有时候为了提升效率,频繁的读写文件并不好,于是出现了字节数组流,即存放在内存中,因此有称之为内存流

其中字节数组流也一种节点流,除了节点流外,还有数据流。数据处理流是用于针对数据类型传输处理的,是一种处理流,即是在节点流之上的增强处理,一般用于序列化和反序列化的时候用到。

字节数组流有:ByteArrayInputStream/ByteArrayOutputStream,通常结合数据流DataInputStream/DataOutputStream

public class DataStream {
	public static void main(String[] args) {
		ByteArrayOutputStream baos=new ByteArrayOutputStream();//创建字节数组流,同时会在内存里面创建数组
		DataOutputStream dos=new DataOutputStream(baos);//对字节数组流外封装成数据处理流
		try {
			dos.writeDouble(Math.random());//利用数据流里面的写入方法,写一个Double类型的随机数据
			dos.writeBoolean(true);
			ByteArrayInputStream bias=new ByteArrayInputStream(baos.toByteArray());//toByteArray()方法是创建一个新分配的字节数组。数组的大小和当前输出流的大小。这里指的是baos这个字节数组
			System.out.println(bias.available());
			DataInputStream dis=new DataInputStream(bias);
			System.out.println(dis.readDouble());
			System.out.println(dis.readBoolean());		
			dos.close();
			dis.close();
		}catch (IOException e) {
			e.printStackTrace();
		}
	}
}