黑马程序员 java_IO流笔记(三)

-------android培训 、java培训、期待与您交流! ----------

File类

用来将文件或者文件夹封装成对象

方便对文件与文件夹的属性信息进行操作

File对象可以作为参数传递给流的构造函数

文件类 file 
将文件或者文件夹封装成对象 方便对文件和文件夹的属性信息进行
操作。(流对象是不能操作文件夹和文件的属性信息)流只能操作数据
File类的常见方法 
1. 创建
   boolean mkdir()创建目录创建的是单级目录
   boolean mkdirs() 创建多级目录 
boolean createNewFile(); :在指定位置创建文件,如果该文件已经存在则不创建,返回false
和输出流不一样,输出流对象已建立就创建文件,并且若文件已存在,会覆盖掉所以这个更合理。
2. 删除
boolean delete();删除失败返回false 
void deleteOnExit();当程序退出时自动删掉指定对象无论出不出现异常
3. 判断
boolean exists() : 文件是否存在
f.isFile() 是否是文件
f.isDirectory() 是否是目录 
isAbsolute() 是否是绝对的的 绝对路径返回ture 即使这个文件不存在 
4. 获取信息 (名字 路径..)
getName();
getPath() 
getParent() 获取父目录 该方法返回的是绝对路径中的父目录,如果封装的是相对目录返回空
如果相对目录中有上一级目录 那么上一级目录就是返回结果
getAbsolutePath() 获取绝对路径 即使文件不存在也能获取路径
long lastModified()获取最后修改的时间
long length() 获取数据体积

import java.io.*;
class  FileDemo
{
	public static void main(String[] args) throws IOException 
	{
		//consMethod();
		method_1();
	}
	public static void method_3()throws IOException
	{
		File f = new File("file.txt");
		sop();//必须先判断该文件封装的对象是否存在通过exists()判断 注意!!
		sop("dir: "+f.isDirectory());//判断是不是目录
		sop("dir: "+f.isFile());//判断是不是文件

	}
	public static void method_2()throws IOException 
	{
		File f = new File("file.txt");

		sop("exists : "+f.exists());//判断文件是否存在 把文件封装成对象的好处
		//sop("execute : "+f.canExecute());//该文件是否能执行
		File dir = new File("aaa\\kk");//当前目录下创建 aaa\kk文件路径
		sop("mkdir :"+dir.mkdir());
	}

	
	public static void method_1()throws IOException 
	{
		File f = new File("file.txt");
		//sop("creat : "+f.createNewFile());// 创建成功返回true
		sop("delete : "+f.delete());//第一次删成返回true
	}
	//创建file对象
	public static void consMethod()
	{
		//将a.txt封装成File对象 可以讲已有的和未出现的文件或者文件夹封装成对象
		File f1 = new File("a.txt");
		//将目录和文件分开两个来存储的, 操作的目录不变,但是后面这个变量变化
		File f2 = new File("C:\\abc","b.txt");
		//
		File d = new File("c:\\abc");
		File f3 = new File(d,"c.txt");

		sop("f1: "+f1); //打印的是路径 封装的是相对的打印就相对封装绝对打印就绝对
		sop("f2: "+f2);
		sop("f3: "+f3);
		File f4 =  new File("c:"+File.separator+"abc\\zz\\a.txt");
		//上面 分隔符这俩 \\不同OS可能会不兼容不跨平台 File.separator 跨平台分隔符
		
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

list 方法

依据里面那个accept方法的返回值来判定它是否要过滤到这些文件 、
要是返回真表示这里面这些文件都是符合条件的 要是返回false则表示里面的
文件都不是符合条件的。
分享个小经验 
在基础阶段学习时用editplus编程 cmd运行时
有时候会出现这个样的问题 就是编译能过 但是运行不了 提示出现的错误是找不到或者无法加载主类 XXX
这个原因有一种可能是 在你在editplus里面主类的文件名跟你保存的java文件的名字是不一样的 比如说名字中
两个字母位置颠倒了。 比如 你主类名字是 FlieDemo 你保存的是FileDemo.java 
这个这个时候 你用javac FileDemo.java 是不会出现任何错误提示的 但是运行之后就会出现
找不到或者无法加载主类 FileDemo
这时候编译不报错 就是运行不了  别蒙圈 检查一下文件名字是否正确

要是返回真表示这里面这些文件都是符合条件的 要是返回false则表示里面的
文件都不是符合条件的。
分享个小经验 
在基础阶段学习时用editplus编程 cmd运行时
有时候会出现这个样的问题 就是编译能过 但是运行不了 提示出现的错误是找不到或者无法加载主类 XXX
这个原因有一种可能是 在你在editplus里面主类的文件名跟你保存的java文件的名字是不一样的 比如说名字中
两个字母位置颠倒了。 比如 你主类名字是 FlieDemo 你保存的是FileDemo.java 
这个这个时候 你用javac FileDemo.java 是不会出现任何错误提示的 但是运行之后就会出现
找不到或者无法加载主类 FileDemo
这时候编译不报错 就是运行不了  别蒙圈 检查一下文件名字是否正确

import java.io.*;

class  FileDemo2
{
	public static void main(String[] args) 
	{
		listDemo();
	}
	public static void listDemo()
	{
		File dir = new File("G:\\v"); 
		String[] arr = dir.list(new FilenameFilter()
		{
			public boolean accept(File dir,String name)
			{
				return true;
			}
		});	
		
		System.out.println("length"+arr.length);
		for(String name : arr)
		{
			System.out.println(name);
		}
	}
}

递归

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

列出指定目录下文件或者文件夹,包含子目录中的内容
也就是列出指定目录下所有内容
因为目录中还有目录 只要使用同一个列出目录功能的函数完成即可
在列出过程中出现的还是目录的话,还可以再次调用本功能。
也就是说 函数自身调用自身 这种表现形式或者叫变成手法 称为递归
递归要注意 
1.限定条件 
2. 递归次数,尽量避免内存溢出

练习 将一个指定目录下的java文件的绝对路径,存储到一个文本文件中
建立一个java文件列表文件
思路
1.对指定的目录进行递归
2 获取递归过程所有的java文件的路径
3 将这些路径存储在集合中
4 将集合中的数据写入到一个文件中

import java.io.*;
import java.util.*;
class  JavaFileList
{
	public static void main(String[] args) 
	{
		File dir = new File("G:\\day20");//把要遍历的目录放里面
		List<File> list = new ArrayList<File>();
		fileToList(dir,dir);
		System.out.println(list.size());//文件太多印出来效果不好 显示个大小

		File file = new File(dir,"javaListFile.txt");//父目录 文件名

		writeToFile(list,file.toString());//toString 绝对路径
	}
	public static void fileToList(File dir,List<File>list)
	{
		File[] flies = dir.listFles();
		for(File file : files)
		{
			if(file.isDirectory())//遇到目录的时候
				fileToList(file,list);
			else//不是的话判断文件名字是否是.java结尾的
			{
				if(flie.getName().endsWith(".java"))
					list.add(file);
			}
		}

	}
	public static void writeToFile(List<File>list,String javaListFile)throws IOException
	{
		BufferedWriter bufw = null; //用缓冲区提高效率
		try
		{
			bufw = new BufferedWriter(new FileWriter(javaListFile)); //缓冲区关联一个文件要往javaListFile里面写
			for(File f : list)//把列表遍历一下子这个时候强化for循环代替迭代器的简便优势就出来了
			{
				String path = f.getAbsolutePath();
				bufw.write(path);
				bufw.newLine();
				bufw.flush();

			}
		}
		catch (IOException e)
		{
			throw e; //处理不了扔出去 上面要声明
		}
			
		finally
		{
			try
			{
				if(bufw!=null)
					bufw.close();
			}
			catch (IOException)
			{
				throw e;
			}
		}
	}
}

IO包中的其他类

Properties是hashtable的子类,
也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串,而不是泛型。
是 集合中和IO技术相结合的集合容器 
该对象的特点可以用于键值对形式的配置文件 。
在加载数据时需要数据有固定格式 键=值
演示 如火热将流中的数据存到集合中进行操作。
想要将info.txt中键值数据存到集合中进行操作
1. 用一个流和info.txt文件关联
2. 读取一个行数据,将该行数据用“=”进行切割
3. 等号左边作为键,右边作为值,存入到properties集合中即可。

import java.io.*;
import java.util.*;
class  PropertiesDemo
{
	public static void main(String[] args)throws IOException 
	{
		loadDemo();
		//method_1();
		//System.out.println("Hello World!");
	}
	public static void loadDemo()throws IOException
	{
		Properties prop = new Properties();//建立一配置文件
		FileInputStream fis = new FileInputStream("info.txt");//输入流跟文件关联
		prop.load(fis);//将流中的数据加载进集合
		//System.out.println(prop);
		prop.list(System.out);

	}
	public static void method_1()throws IOException
	{
		BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));//数据流跟文件关联
		String line = null;//行中转
		Properties prop = new Properties();

		while ((line = bufr.readLine())!=null)
		{
			//System.out.println(line);//打印行
			String[] arr = line.split("=");//用等号分开
			//System.out.println(arr[0]+"------"+arr[1]);
			prop.setProperty(arr[0],arr[1]);
		}
		bufr.close();
		System.out.println(prop);
	}
}

删除一个带内容的目录。
删除原理
在window中,删除目录从里面往外删除
既然如此 就需要用到递归 

java删除是不走回收站的 直接删不能恢复

import java.io.*;
class RemoveDir 
{
	public static void main(String[] args) 
	{
		File dir =new File("G:\\abc");
		removeDir(dir);
		//System.out.println("Hello World!");
	}
	public static void removeDir(Flie dir)
	{
		File[] files = dir.listFiles();
		for (int x = 0;x<files.length ;x++ )
		{
			if(files[x].isDirectory()) //判断如果是目录的话,再调用
				removeDir(files[x]);
			else
				System.out.println(files[x].toString()+":文件被干掉了 :"+files[x].delete()); //如果不是目录则删除
		}
		System.out.println(dir+"::文件夹被干掉了::"+dir.delete());
	}
}

Runcount 用于记录应用程序运行次数
如果使用次数已到,那么给出注册提示 
很容易想到的是 计数器 
可是该计数器 定义在程序中,随着程序的运行而在内存中存在,并进行自增 
可是随着该应用程序的退出,该计数器也在内存中消失了下一次再启动改程序
又重新开始从0计数 这样不是我们想要的。
我们想要的是 程序即使结束,该计数器的值也存在,下一次程序启动会先加载该计数器的值
并加1后重新存储起来
所以要建立一个配置文件用于记录该软件的使用次数。
该配置文件使用键值对的形式,这样便于阅读数据并操作数据。
键值对数据时map集合
数据时以文件形式存储,使用io技术
那么map +io ————>propperties 
配置文件可以实现应用程序数据的共享

import java.io.*;
import java.util.*;
class  RunCount
{
	public static void main(String[] args) throws IOException
	{
		Properties prop = new Properties(); //搞一配置文件对象 集合
		 File file = new File("count.ini");// 把文件封装成对象
		if(!file.exists())
			file.createNewFile();
			
		FileInputStream fis = new FileInputStream(file);//文件对象加载到流中
		prop.load(fis);									//流放到集合中
		int count = 0;									// 计数器
		String value = prop.getProperty("time");		// 根据time键取值 第一次是空的
		if(value!=null)//如果不等于空 就记录一次
		{	
			count = Integer.parseInt(value);			//记录次数
			if (count>=5)
			{
				System.out.println("次数已到请注册");   //到次数信息
				return ;
			}
		}
		count++;
		prop.setProperty("time",count+""); //增完了装集合里

		FileOutputStream fos = new FileOutputStream(file); //装完集合了 写回去
		prop.store(fos,""); //集合中的数据写入输出流
		fis.close(); //关流
		fos.close();
		//System.out.println("Hello World!");
	}
}

实现分段传输 就是把一个大的文件分成几个小的文件传输

import java.io.*;
import java
class SplitFile 
{
	public static void main(String[] args) throws IOException
	{
		splitFile();
		//System.out.println("Hello World!");
		merge();
	}
	//合并
	public static void merge() throws IOException
	{
		//用这个集合快点  数据存到数组里面用枚举取出来
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		for(int x=1;x<=3;x++)
		{
			al.add(new FileInputStream("C:\\splitfiles\\"+x+".part"));//碎片加数组里面
		}
		final Iterator<FileInputStream> it = al.terator();
		Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
		{
			public boolean hasMoreElements()
			{
				return it.hasNext();
			}
			public FileInputStream nextElement()
			{
				return it.next();
			}

		};

		SequenceInputStream sis = new SequenceInputStream(en);
		//上面一堆就是为了获取源..
		//搞到文件里面
		FileOutputStream fos = new FileOutputStream("C:\\splitfiles\\0.bmp");
		byte[] buf = new byte[1024];
		int len = 0;
		while ((len=sis.read(buf))!=-1)
		{
			fos.write(buf,0,len);
		}
		fos.close();
		sis.colse();

	}
	
	
	//分段
	public static void splitFile()throws IOException
	{
		FileInputStream fis = new FileInputStream("c:\\1.bmp"); //输入流关联一个文件

		FileOutputStream fos =  null;//建立输出流

		byte[] buf = new byte[1024*1024]; //搞一字节数组存图片

		int len = 0;
		while ((len=fis.rean(buf))!=-1) //一直不等于-1就表示装了1M 的数据 循环几次就创建几个流 就分几part
		{
			fos = new FileOutputStream("C:\\splitfiles\\"+(count++)+".part"); //每次存一片
			fos.write(buf,0,len);//写里面去
			fos.close();//写完就关上 
		}
		fis.close();
	}
}
打印流
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream

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

4,字符输出流,Writer。

import java.io.*;

class  PrintStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader bufr = 
			new BufferedReader(new InputStreamReader(System.in));

		PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);

		String line = null;

		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			out.println(line.toUpperCase());
			//out.flush();
		}

		out.close();
		bufr.close();

	}	
}
用于操作字节数组的流对象
ByteArrayInputStream 在构造的时候,需要接收数据源,而且数据源是一个字节数组。
ByteArrayOutputStream 在构造的时候不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组
这就是数据目的。
因为这两个流对象都操作的数组 ,并没有使用系统资源,所以不需要进行close关闭。关了也能用
在流操作规律讲解时
源设备
键盘 System.in 硬盘FileStream  内存 ArrayStream
目的设备
控制台System.out 硬盘FileStream 内存ArrayStream

用流的读写思想操作数组

import java.io.*;
class  BASDemo
{
	public static void main(String[] args) 
	{
		//数据源
		ByteArrayInputStream bis = new ByteArrayInputStream("ASDFGHT".getBytes());
		//数据目的
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		System.out.println(bos.size());
		int by = 0;
		while ((by=bis.read())!=-1)  //不等于-1就一直往目的数组写
		{
			bos.write(by);
		}
		System.out.println(bos.size());
		System.out.println(bos.toString());
		
		
		//System.out.println("Hello World!");
	}
}
write() 最低8位写入
writeIny() 写32位进去 
静态时不能序列化的  只能把堆里的数据进行序列化
要是想把堆内存里面的数据不想让他序列化 那么 可以在其前面加一个 transient

RandomAccessFile
这个类啥用啊 
多线程下载  整个文件分为几个线程下载。
该类不算是io体系中的子类 而是直接集成在object 但是他是io包中的成员
因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组中的元素进行操作
可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。
其实完成读写的原理就是 内部封装了字节输入和输出流
通过构造函数可以看出 该类智能操作文件。而且操作文件还有模式
该模式只 该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等。
如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

import java.io.*;
class  RandomAccessFileDemo
{
	public static void main(String[] args) throws IOException
	{
		//writeFile();
	readFile();
		System.out.println("Hello World!");
	}
	public static void readFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","r"); //建立一个度
		raf.seek(8*1);//取第二个人 随机读 随机写 还能随机修改 <-----------很重要这个访法 
		byte[] buf = new byte[4];//建立一个四个字节的数组来存名字 这个长度跟要取的字节数对应
		raf.read(buf); //把raf里的数据读到数组里
		String name = new String(buf);//数组弄成字符串型
		int age = raf.readInt();
		System.out.println("name="+name+"--age-"+age);
		raf.close();



	}
	public static void  writeFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
		raf.write("李四".getBytes());
		raf.writeInt(97);
		raf.write("张三".getBytes());
		raf.writeInt(98);
		raf.close();

	}
}
RandomAccessFile
该类不算是io体系中的子类 而是直接集成在object 但是他是io包中的成员
因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组中的元素进行操作
可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。
其实完成读写的原理就是 内部封装了字节输入和输出流
通过构造函数可以看出 该类智能操作文件。而且操作文件还有模式
该模式

import java.io.*;
class  RandomAccessFileDemo
{
	public static void main(String[] args) throws IOException
	{
		writeFile();
		System.out.println("Hello World!");
	}
	public static void  writeFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
		raf.write("李四".getBytes());
		raf.write(97);
		raf.close();

	}
}

字符编码
字符流的出现为了方便操作字符。
更重要是的加入了编码转换。
通过子类转换流来完成。
InputStreamReader
OutputStreamWriter
在两个对象进行构造的时候可以加入字符集。
编码表的由来
计算机只能识别二进制数据,早期由来是电信号。
为了方便应用计算机,让它可以识别各个国家的文字。
就将各个国家的文字用数字来表示,并一一对应,形成一张表。
这就是编码表。
常见的编码表
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。
......
转换流的编码应用
可以将字符以指定编码格式存储。
可以对文本数据指定编码格式来解读。
指定编码表的动作由构造函数完成。
编码:字符串----->字节数组
解码:字节数组——>字符串


------IO-over--------

-------android培训 、java培训、期待与您交流! ----------



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值