Java基础——IO流(三)

File类

  • 用来将文件或者文件夹封装成对象
  • 方便对文件与文件夹的属性信息进行操作
  • File对象可以作为参数传递给流的构造函数
  • 了解File类的常用方法

创建文件对象


//创建一个文件对象的几种方法
import java.io.*;
public class FileDemo {
	public static void main(String[] args) 
	{
		//通过绝对路径创建对象
		File f1 = new File("E:\\others\\java\\day20file\\abc\\a.txt");
		sop("f1 = "+f1);
		//通过相对路径创建对象
		File f2 = new File("b.txt");
		sop("f2 = "+f2);

		//指定父目录,和子文件名称
		File f3 = new File("E:\\others\\java\\day20file\\123","c.txt");
		sop("f3 = "+f3);

		//目录通过引用的方法
		File d =  new File("E:\\others\\java\\day20file\\haha");
		File f4 = new File(d,"d.txt");
		sop("f4 = "+f4);
		//目录可以引用,但是文件不可以引用

	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

创建文件对象

这里边的\分割符只适用于Windows系统,不是跨平台的,

File.separator,与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。

使用起来是这样的。

File f = new File("E:"+File.separator+"others"+File.separator+"java"+File.separator+"day20file"+File.separator+"abc.txt");

File常见类的方法:

  1. 创建
    1. boolean createNewFile();在指定的位置创建文件,如果该文件已经存在,则不创建,返回false,和输出流不一样,输出流对象一建立创建文件,而且文件已经存在,会覆盖
    2. boolean mkdir();创建文件夹
    3. boolean mkdirs();创建多级文件夹
  2. 删除
    1. boolean delete();删除失败,返回false
    2. void deleteOnExit();在程序退出时删除指定文件
  3. 判断
    1. boolean exists();文件是否存在。
    2. isFile();判断文件对象是否是文件(该文件必须先 存在才返回真)
    3. isDirectory();判断文件对象是否是路径(文件夹)(该路径必须先存在才返回真)
    4. isHidden();判断文件是否隐藏
    5. isAbsolute();判断路径是否为绝对路径(该路径可以不用存在)
  4. 获取信息

简单的方法操作演示。

//file类中的基本方法
import java.io.*;
public class FileDemo2 {
	//为了演示看起来简洁,先将异常抛出去
	public static void main(String[] args) throws IOException 
	{
		File f = new File("a.txt");//这是创建了一个对象,实际上什么都没有
		File f0 = new File("b.txt");

		//将该对象创建出来 实际的文件
		sop("a.txt文件是否创建成功?"+f.createNewFile());
		sop("b.txt文件是否创建成功?"+f0.createNewFile());

		//删除文件
		//f0.deleteOnExit()//这是在虚拟机退出的时候删除文件
		sop("文件b.txt删除成功了吗?"+f0.delete());//这是在代码执行的时候删除文件
		//创建一个路径
		File f1 = new File("abcd");
		sop("abcd文件夹是否创建成功"+f1.mkdir());

		//创建多级目录
		File f2 = new File("abc"+File.separator+"qq"+File.separator+"haha"+File.separator+"www");
		sop("“礼物是否准备好?”"+f2.mkdirs());

		//判断文件是否存在?
		sop("a.txt文件是否存在呢?"+f.exists());
		sop("abcd文件夹是否存在呢?"+f1.exists());
		sop("abc文件夹是否存在呢?"+f2.exists());

		//判断文件对象是文件还是文件夹
		sop("f是文件吗?"+f.isFile());
		sop("f1是文件吗?"+f1.isFile());
		sop("f2是文件吗?"+f2.isFile());
		sop("f1是文件夹吗?"+f1.isDirectory());
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

创建删除判断方法的演示

File对象中的获取信息的方法

getName();获取对象名称
getPath();获取相对路径
getAbsolutePath();获取绝对路径
getParent();获取对象的父目录
long lastModified();获取文件最后一次被修改的时间
long length();获取文件的长度

//File类方法中的获取方法类

import java.io.*;
public class FileDemo3 {
	public static void main(String[] args) 
	{
		File f1 = new File("abc\\a.txt");
		File f2 = new File("b.txt");

		//不创建实际文件也可以进行获取
		sop(f1.getPath());//获取相对路径
		sop(f1.getAbsolutePath());//获取绝对路径
		sop(f2.getPath());

		sop(f1.getParent());//获取父目录
		sop(f2.getParent());

	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

获取方法演示

这里需要注意的是:

getParent方法,返回的是绝对路径中的父目录,如果获取的是相对路径,返回null
如果相对路径中有上一层目录,那么该目录就是返回结果。

替换文件名的方法演示:

//替换文件名称的方法演示
import java.io.*;
public class FileDemo4 {
	public static void main(String[] args) throws IOException
	{
		File f1 = new File("E:\\others\\java\\day20file\\a.txt");
		File f2 = new File("E:\\others\\java\\day20file\\b.txt");

		f1.createNewFile();//将f1对象创建成存在的文件

		//将f1文件名替换成f2上的名称
		sop("renameTo:"+f1.renameTo(f2));
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果为:

第一次运行,打印结果为真,第二次运行,打印结果为假
文件名由a.txt变为b.txt

File类中的其他方法演示:

static listRoots();//列出可用的文件系统根,也就是盘符

//File类中其他方法的演示
import java.io.*;
public class FileDemo4 {
	public static void main(String[] args) throws IOException
	{
		File[] files = File.listRoots();
		for(File f :files )
		{
			sop(f);
		}
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

获取文件的系统根

list方法:返回一个字符串数组,这些字符串指定此路径名表示的目录中的文件和目录。

演示:

//列出指定目录中所有的文件
import java.io.*;
public class FileDemo4 {
	public static void main(String[] args) throws IOException
	{
		//指定一个目录名,这个目录必须存在
		File f = new File("e:\\others\\java");
		//根据list方法获取到目录中的所有文件和文件夹的名称
		String[] lists = f.list();
		for(String name:lists)
		{
			sop(name);
		}
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

list方法的用法

能不能获取我想要的文件呢?比如说获取后缀名为.class的文件呢?

list方法的重载方法,可以做到,
在list方法的参数中传一个FilenameFilter(接口)过滤器;然后复写里面的accept方法,

原理是:list方法可以获取到该目录下所有的文件,accept方法读取到所有的文件名之后,进行条件的判断,是不是以.class结尾的,如果是,则返回真,如果不是则返回假

//用过滤器选出想要的文件,并打印出来
import java.io.*;
public class FileDemo4 {
	public static void main(String[] args) throws IOException
	{
		//指定一个目录名,这个目录必须存在
		File f = new File("e:\\others\\java\\day20file");
		//根据list方法获取到目录中的所有文件和文件夹的名称
		String[] lists = f.list(new FilenameFilter()//因为FilenameFilter是一个接口,所以这里用内部类的方法传参数
		{
			//复写里边的方法accept,参数为一个file对象(目录)一个String类型的文件名
			public boolean accept(File dir,String name)
			{
				return name.endsWith(".class");//只要list方法读取到的文件的名称的后缀名为.class,就返回真
			}
		});
		for(String name:lists)//然后把集合中的内容打印出来
		{
			sop(name);
		}
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

这里写图片描述

这个list方法可以获取到的文件名,也就是字符串类型的,
listFiles方法可以获取到文件对象File,可以进行更多的操作。

//用过滤器选出想要的文件对象,并打印出来获取到的文件名和长度
import java.io.*;
public class FileDemo4 {
	public static void main(String[] args) throws IOException
	{
		File dir = new File("e:\\others\\java\\day20file");
		//使用listFiles方法获取到所有的文件对象
		File[] files = dir.listFiles();
		for(File file:files)
		{
			sop(file.getName()+"....."+file.length());
		}
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

listFiles方法获取所有的文件对象

发现,指定目录下的文件夹的长度是获取不到长度的,

那么需求来了,,想要获取到指定目录中目录中的文件,也就是目录下还有目录,需要将里边的所有文件打印出来。

因为在目录中还有目录,只要使用同一个列出目录功能的函数完成即可
在列出过程中出现还是目录的话,还可以再次调用本功能
也就是函数自身调用自身
这种表现形式,或者变成手法,称为递归。

用代码来演示递归:

//列出目录中的所有文件,以及目录中子目录中的所有文件
import java.io.*;
public class AllFileList {
	public static void main(String[] args) 
	{
		File dir = new File("e:\\others\\java\\day20file");
		getDir(dir);//获取目录中文件的方法
	}
	public static void getDir(File dir)
	{
		sop(dir);//先打印一次目录名
		File[] files = dir.listFiles();//获取所有的文件对象
		for(File f:files)
		{
			if(f.isDirectory())//判断如果获取到的文件对象是目录,就再调用一次自己的方法
				getDir(f);		//这种在自己的方法中再一次调用自己的方法的模式叫做递归
			sop(f.getName());//如果不是目录就直接打印出来对象的名字
		}
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

获取到路径中的所有文件

使用递归时要注意
1,要有限定条件,否则就陷入了死循环
2,要注意递归的次数,尽量避免内存溢出。

演示几个递归的例子:

public class DiGuiTest {
	public static void main(String[] args) 
	{
		toBin(6);//110;
		sop(getSum(10));//55
	}
	//获取一个十进制数的二进制数
	public static void toBin(int num)
	{
		//判断如果num值大于0.就调用一次自己的方法,然后再打印数据
		if (num>0)
		{
			toBin(num/2);
			sop(num%2);
		}
	}
	//获取一个数从1加到他的总和
	public static int getSum(int n)
	{
		if(n==1)
			return 1;
		else
			return n+getSum(n-1);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

再回来说之前打印目录中的文件的例子,打印的很难看,没有层次感,想在每一个目录下边加两个空格,于是就要获取到每个目录的层次:

//列出目录中的所有文件,以及目录中子目录中的所有文件
import java.io.*;
public class AllFileList {
	public static void main(String[] args) 
	{
		File dir = new File("e:\\others\\java\\day20file");
		getDir(dir,0);//获取目录中文件的方法
	}
	public static void getDir(File dir,int level)//该方法可以有层次的获取目录中的文件
	/*
	具体思路是,
	每调用一次该方法,level的值自增一次
	打印文件内容的时候,在前边吧层次分割符加上,也就是加上getLevel方法就好了
	*/
	{
		sop(getLevel(level)+dir.getPath());
		level++;
		File[] files = dir.listFiles();
		for(File f:files)
		{
			if(f.isDirectory())
				getDir(f,level);		
			sop(getLevel(level)+f.getName());
		}
	}
	public static String getLevel(int level)//该方法可以给每一个层次前边添加空格,作为层次分割符号
	/*
	具体思路是,在一个缓冲区中先加入一个|--符号,
	传进来的数字是多少,就在该符号前边添加多少个空格
	最后将字符串中的数据全部返回去
	*/
	{
		StringBuilder sb = new StringBuilder();
		sb.append("|--");
		for(int x = 0;x<level;x++)
		{
			sb.insert(0,"  ");
		}
		return sb.toString();
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果为:

具有层次的获取目录中的文件

需求:删除一个带内容的目录

删除原理
在Windows中,删除目录是从里面往外面删除的,
既然是从里往外删除,就用到了递归。

//删除目录中的文件,连同目录也删了
import java.io.*;
public class DeleteDemo {
	public static void main(String[] args) 
	{
		File dir = new File ("e:\\others\\java\\day20file\\abcd");
		deleteDir(dir);
	}
	public static void deleteDir(File dir)
	{
		File[] files = dir.listFiles();
		for(File f : files)
		{
			if(f.isDirectory())
				deleteDir(f);//如果碰到目录文件,再次调用自己的方法
			else
				f.delete();
		}
		//里边的东西都删完了,该删最外面的目录了
		dir.delete();
	}
}

练习:将一个指定目录下的java文件的绝对路径,存储到一个文本文件中
建立一个java文件列表文件

思路:
1,对指定的目录进行递归
2,获取递归过程所有的java文件的路径
3,将这些路径存储到集合中

//将目录中所有的java文件的绝对路径存储到一个txt文件中
import java.io.*;
import java.util.*;
public class JavaFileList {
	public static void main(String[] args) 
	{
		File dir = new File("e:\\others\\java");//指定一个目录,要把这里边的所有java文件读出来,
		List<File> list = new ArrayList<File> ();//按照思路,先把读到的所有的文件对象存到集合中
		File file = new File(dir,"javafilelist.txt");//所有的数据要写入的文件定义好
		getDir(dir,list);//该方法将dir目录中的所有符合条件的文件对象装进集合中
		listToText(list,file);//该方法将集合中的对象的绝对路径值写入到文件中
	}
	public static void getDir(File dir,List<File> list)
	{
		File[] files = dir.listFiles();
		for(File f : files)
		{
			if(f.isDirectory())
				getDir(f,list);
			else
			{
				if(f.getName().endsWith(".java"))//如果符合条件,将对象装入到集合中
					list.add(f);
			}
		}
	}
	public static void listToText(List<File> list,File file)//该方法将集合中的java文件对象的绝对路径写入到文件中
	{
		BufferedWriter bufw = null;
		try
		{
			bufw = new BufferedWriter(new FileWriter(file));
			for(File f1:list)
			{
				String path = f1.getAbsolutePath();
				bufw.write(path);
				bufw.newLine();
				bufw.flush();
			}
			
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			if(bufw!=null)
				try
				{
					bufw.close();				
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
		}
	}
}

运行结果:

最后生成的文件

Properties简述

Properties是hashtable的子类
也就是说它具备map集合的特点,而且它里边存储的键值都是字符串(不用定义泛型)

是集合中和IO技术相结合的集合容器

该对象的特点:可以用于键值对形式的配置文件

在加载数据时,通常有固定格式:键=值

比如:EditPlus中可以设置自己的字体颜色,当我设置以后把软件关掉,重新开启之后,字体颜色还是改过之后的,说明,我们改的属性在软件的配置文件中,软件每次一运行,都会执行他的配置文件。

Properties的简单操作:

//实现Properties的存取

import java.io.*;
import java.util.*;
public class PropertiesDemo {
	public static void main(String[] args) 
	{
		Properties prop = new Properties();//创建一个新的Properties对象
		set(prop);//在里边设置键值对
		modificatoin(prop);//修改里边的键值对
		get(prop);//获取键值对
	}
	public static void set(Properties prop)//该方法用来设置里边的键值对
	{
		//使用setProperty();
		prop.setProperty("zhangsan","39");
		prop.setProperty("lisi","50");
		System.out.println(prop);
	}
	public static void modificatoin(Properties prop)//修改属性键值对的内容
	{
		//还是用setProperty()方法
		prop.setProperty("lisi","88");
	}
	public static void get(Properties prop)//获取属性键值对中的信息
	{
		Set<String> names = prop.stringPropertyNames();//获取到键的名称,并存进set集合中
		for(String name:names)
		{
			System.out.println("name = "+name+".........."+"value = "+prop.get(name));
		}
	}
}

运行结果:

Properties方法演示

那么如何将流中的数据存储到集合中,
就是将info.txt中的数据加载进prop中?

//将流中的数据加载进集合
import java.io.*;
import java.util.*;
/*
思路是:
将一个文件和读取流相关联
将读取到的整行的数据,用=分割开,作为键和值
将分隔开的字符作为键和值存储金prop中
*/

//这里为了演示看起来方便,先将异常抛出,不予处理
public class FileToProp {
	public static void main(String[] args) throws IOException
	{
		method_2();
	}
	public static void method_1() throws IOException
	{
		//该方法是按照整体思路走的,可是实现将流中的数据存储进prop中。
		BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
		Properties prop = new Properties();
		String line = null;
		while((line = bufr.readLine())!=null)
		{
			//读取到的数据用=分割开
			String[] strs = line.split("=");
			//将=两边的数据分别加载进集合
			prop.setProperty(strs[0],strs[1]);
		}
		System.out.println(prop);
	}


	public static void method_2() throws IOException
	{
		//在Properties类中提供了将流中的数据加载进集合的方法load
		BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
		Properties prop = new Properties();
		prop.load(bufr);
		System.out.println(prop);
	}
}

运行结果:

将文件中的数据加载进集合

代码中可以发现,使用Properties中的方法方便很多,

想到,如果我将数据加载进内存的时候,可不可以对数据进行修改呢?

//将流中的数据加载进集合
import java.io.*;
import java.util.*;
/*
思路是:
将一个文件和读取流相关联
将读取到的整行的数据,用=分割开,作为键和值
将分隔开的字符作为键和值存储金prop中
*/

//这里为了演示看起来方便,先将异常抛出,不予处理
public class FileToProp {
	public static void main(String[] args) throws IOException
	{
		method_2();
	}
	public static void method_1() throws IOException
	{
		//该方法是按照整体思路走的,可是实现将流中的数据存储进prop中。
		BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
		Properties prop = new Properties();
		String line = null;
		while((line = bufr.readLine())!=null)
		{
			//读取到的数据用=分割开
			String[] strs = line.split("=");
			//将=两边的数据分别加载进集合
			prop.setProperty(strs[0],strs[1]);
		}
		System.out.println(prop);
	}


	public static void method_2() throws IOException
	{
		//在Properties类中提供了将流中的数据加载进集合的方法load
		BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
		Properties prop = new Properties();
		//将流中的数据加载进内存
		prop.load(bufr);

		//在这里对数据进行修改:
		prop.setProperty("lisi","3");

		//将集合中的元素输出到指定的输出流
		prop.list(System.out);
	}
}

运行结果发现,打印在控制台上的数据,是修改之后的数据,但是原文件中的数据还是以前的,也就是说修改后的数据没有保存在配置文件中。

prop.store方法,store(Writer writer, String comments)
将属列表中的数据,写入到输出流中,comments是注释,写不写都行的

对代码进行修改:

//将流中的数据加载进集合
import java.io.*;
import java.util.*;


//这里为了演示看起来方便,先将异常抛出,不予处理
public class FileToProp {
	public static void main(String[] args) throws IOException
	{
		method_2();
	}
	

	public static void method_2() throws IOException
	{
		//在Properties类中提供了将流中的数据加载进集合的方法load
		FileInputStream fis = new FileInputStream("info.txt");
		Properties prop = new Properties();
		//将流中的数据加载进内存
		prop.load(fis);

		//在这里对数据进行修改:
		prop.setProperty("lisi","39");

		//将集合中的元素输出到指定的输出流
		prop.list(System.out);

		//创建一个输出流,和文件关联
		FileOutputStream fos = new FileOutputStream("info.txt");
		//这里注意,因为这里文件读取流和文件写入流关联的是同一个文件,
		//不可以在相邻的两行中连续创建文件的读取流和写入流。

		//将列表中的文件再写入到文件中
		prop.store(fos,"jaja");
		fis.close();
		fos.close();
	}
}

运行结果为:

再将列表中的数据写入到文件中

练习:建立一个配置文件,里边存储软件的运行次数,如果次数到了,那么给出注册提示。

思路:很容易想到的是计数器
可是该计数器定义在程序中,随着程序的运行而在内存中存在并进行自增
可是随着该应用程序的退出,该计数器也在内存中消失了

下一次再启动程序,又从0开始计数。
这不是我们想要的,

程序即使结束,该计数器的值也存在
下次程序启动会先加载该计数器的值,并加1后重新存储起来

键值对数据是map集合
数据是以文件形式存数的,使用IO技术
那么map+IO-->properties
//使用配置文件控制程序执行的次数
import java.io.*;
import java.util.*;
public class Runcount {
	public static void main(String[] args) throws IOException
	{
		File file = new File("count.ini");
		if(!file.exists())
			file.createNewFile();
		FileInputStream fis = new FileInputStream(file);
		Properties prop = new Properties();
		//每运行一次,先读取配置文件中的额信息
		prop.load(fis);
		//找键为time的值,第一次找是找不到的,返回null,count++后存进列表中
		//如果找到了,把count的值取出来自增后存进列表中
		String value = prop.getProperty("time");
		int count = 0;
		if(value!=null)
		{
			count = Integer.parseInt(value);
			if(count>=4)
				System.out.println("您好,您的试用次数已到,请您注册");
		}
		count++;
		prop.setProperty("time",count+"");//Properties中的元素都是字符串,所以count+""表示将count转换为字符串
		//最后将雷彪中的信息写进文件中。
		FileOutputStream fos = new FileOutputStream(file);
		prop.store(fos,"");
		fis.close();
		fos.close();
	}
}

运行结果为:

设置配置文件的例子

打印流

该流提供了打印方法可以将各种数据类型的数据都原样打印

字节打印流
PrintStream
构造函数可以接收的参数类型
1,file对象 File
2,字符串路径 String
3,字节输出流 OutputStream

字符打印流
PrintWriter
构造函数可以接收的参数类型
1,file对象 File
2,字符串路径 String
3,字节输出流 OutputStream
4,字符输出流 Writer

简单的演示一下,普通的获取键盘录入的数据,然后打印在控制台上

//打印流的方法演示
//我想读取键盘录入,将键盘上敲的字符直接打印在控制台上
import java.io.*;
public class PrintStreamDemo{
	public static void main(String[] args) throws IOException
	{
		//开启两个流对象,PrintWriter对象比Writer对象强大,
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(System.out);
		String line = null;
		while ((line = bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			out.println(line.toUpperCase());//自带换行的方法
			out.flush();//写完要记得刷新,如果不刷新的话,他会将读取到的数据写入到缓冲区中
		}
		bufr.close();
		out.close();
	}
}

运行结果:
PrintWriter

PrintWriter的强大之处还在于,可以自己刷新

在构造方法时可以看到:
构造方法摘要

只有println方法输出的时候,才会用自己刷新的。只要在构造方法的时候,流参数后边加一个true

//打印流的方法演示
//我想读取键盘录入,将键盘上敲的字符直接打印在控制台上
import java.io.*;
public class PrintStreamDemo{
	public static void main(String[] args) throws IOException
	{
		//开启两个流对象,PrintWriter对象比Writer对象强大,
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(System.out,true);
		String line = null;
		while ((line = bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			out.println(line.toUpperCase());//自带换行的方法
			//上边有了true,方法println会会自动刷新,这里可以不用写刷新方法
		}
		bufr.close();
		out.close();
	}
}

一样可以运行的,
println方法自动刷新

那么我想将键盘录入的数据装进一个文件里呢?
只要将文件对象封装成流对象就可以实现读写时候的自动刷新了。

//打印流的方法演示
//我想读取键盘录入,将键盘上敲的字符直接打印在一个文本文件中
import java.io.*;
public class PrintStreamDemo{
	public static void main(String[] args) throws IOException
	{
		//只要在这里创建一个文件对象
		File file = new File("a.txt");
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		//在这里将文件包装成流对象,再传入true值,就可以实现流的自动刷新。
		PrintWriter out = new PrintWriter(new FileWriter(file),true);
		String line = null;
		while ((line = bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			out.println(line.toUpperCase());
		}
		bufr.close();
		out.close();
	}
}

运行结果:

键盘录入数据

文件中写入的文字

SequenceInputStream合并流对象

SequenceInputStream可以将多个流对象合并成一个大的流对象。
形成一个流对象的串联模式。

比如:将三个文件中的数据要打印到同一个文件中,需要建立三个流对象,如果一个一个的往里边存的话,就麻烦了,所以这里可以将三个流对象合并成一个大的流对象。

构造方法

构造方法可以看出来,有两个流对象可以直接将流对象传进去,
如果流对象多的话,直接用Enumeration集合中,(Enumeration集合是Vector接口中的子类)

示例如下:

//合并流演示
//将1.txt和2.txt和3.txt中的文字连续写入到4.txt中
import java.io.*;
import java.util.*;
public class SequenceDemo {
	public static void main(String[] args) throws IOException
	{
		//先创建集合,将文件封装成流对象存入集合中
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		v.add(new FileInputStream("1.txt"));//文件中都是数字1
		v.add(new FileInputStream("2.txt"));//文件中都是数字2
		v.add(new FileInputStream("3.txt"));//文件中都是数字3
		//将集合中的元素用枚举遍历出来,交给一个对象en
		Enumeration<FileInputStream> en = v.elements();

		//万事具备,创建大流
		SequenceInputStream sis = new SequenceInputStream(en);

		//创建目标文件的流对象
		FileOutputStream fos= new FileOutputStream(new File("4.txt"));
		
		//开始用字节流读取文件
		byte[] buf = new byte[1024];
		int len = 0;
		while((len = sis.read(buf))!=-1)
		{
			fos.write(buf,0,len);
		}
		fos.close();
		sis.close();
	}
}

运行结果为:

SequenceInputStream

文件切割
将文件切割成相等的几部分,
思路:
创建一个读取流对象,和要切割的文件相关联,
在创建一个写入流的空引用,
开始读取文件,创建一个固定大小的容器,读到容器大小的数据就新创建一个写入流对象,写完立马就把流关掉,
具体代码演示:

//切割文件
import java.io.*;
import java.util.*;
public class SplitFile {
	public static void main(String[] args) 
	{
		File file = new File("1.mp3");
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try
		{
			//读取流关联文件
			fis = new FileInputStream(file);
			//固定缓冲区的长度为1兆
			byte[] buf = new byte[1024*1024];
			int len = 0;
			int count = 1;
			while ((len = fis.read(buf))!=-1)
			{
				try
				{
					//只要读到了一兆的数据,马上创建一个写入流对象,将数据写进去,写完立马关资源
					fos = new FileOutputStream("e:\\others\\java\\day20file\\splitfile\\"+((count++)+".part"));				
					fos.write(buf,0,len);
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
				finally
				{
					if(fos!=null)
						fos.close();
				}
				//当再次读够一兆数据的时候,新开一个写入流对象,写入数据
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				if(fis!=null)
				fis.close();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}

运行结果:

切割下的文件

那么能切割就可以把碎片文件拼在一起:用的是SequenceINputStream的方法

//切割文件
import java.io.*;
import java.util.*;
public class SplitFile {
	public static void main(String[] args)
	{
		spiltFile();
		pinJie();
	}
	//该方法可以将碎片文件拼接在一起
	public static void pinJie()
	{
		//Vector效率低,所以这里用ArrayList集合存数据
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		for (int x = 1;x<6 ;x++ )
		{
			try
			{
				al.add(new FileInputStream("splitfile\\"+x+".part"));			
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		//而SequenceInputStream需要的参数是Enumeration的,这里就要将ArrayList中的数据用枚举的方式取出来
		final Iterator<FileInputStream> it = al.iterator();
		//因为Enumeration是一个接口,里边只有两个方法,所以可以给他创建子类对象,只要覆盖两个方法就可以了
		Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
		{
			public boolean hasMoreElements()
			{
				return it.hasNext();
			}
			public FileInputStream nextElement()
			{
				return it.next();
			}
		};
		//开始用SequenceInputStream获取大流,写数据
		SequenceInputStream sis = null;
		FileOutputStream fos  = null;
		try
		{
			sis = new SequenceInputStream(en);
			fos = new FileOutputStream(new File("splitfile\\2.mp3"));
			byte[] buf = new byte[1024];
			int len = 0;
			while((len = sis.read(buf))!=-1)
			{
				fos.write(buf,0,len);
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			if(sis!=null)
				try
				{		
					sis.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
			if(fos!=null)
			{
				try
				{
					fos.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
		
	}

	//该方法可以将文件切割开
	public static void spiltFile()
	{
		File file = new File("1.mp3");
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try
		{
			//读取流关联文件
			fis = new FileInputStream(file);
			//固定缓冲区的长度为1兆
			byte[] buf = new byte[1024*1024];
			int len = 0;
			int count = 1;
			while ((len = fis.read(buf))!=-1)
			{
				try
				{
					//只要读到了一兆的数据,马上创建一个写入流对象,将数据写进去,写完立马关资源
					fos = new FileOutputStream("e:\\others\\java\\day20file\\splitfile\\"+((count++)+".part"));				
					fos.write(buf,0,len);
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
				finally
				{
					if(fos!=null)
						fos.close();
				}
				//当再次读够一兆数据的时候,新开一个写入流对象,写入数据
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				if(fis!=null)
				fis.close();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}

运行结果:

将文件碎片拼接在一块

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值