黑马程序员——Java基础---IO流(File类、Properties类、其他流)

-------  android培训 java培训 、java学习型技术博客、期待与您交流! ----------
第一讲 File类
一、简述
  • File类:文件和目录路径名的抽象表现形式。
  • 作用:
    • 用来将文件或者文件夹封装成对象。方便于对文件或文件夹的属性信息进行操作。
  • 特点:
    • 流只能操作数据,而想要操作数据被封装的文件的信息必须用File对象。
    • File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变
    • File对象可以作为参数传递给流的构造函数。
二、创建对象
  • 三种创建方式
    1. File file = new File("a.txt");
      • 将a.txt封装成File对象。可以将已有的和未出现的文件或者文件夹封装成对象。
    2. File file = newFile("e:\\abc","b.txt");
      • 将文件所在目录路径和文件一起传入,指定文件路径。
    3. File f = new File("e:\\abc"); File file = new File(f,"c.txt");
      • 将文件目录路径封装成对象。再创建文件对象。降低了文件于父目录的关联性。
三、常见方法:
  1. 创建:
    • boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
      • 和输出流不一样,输出流对象一建立就创建文件,而文件已经存在,会覆盖。
    • boolean mkdir():创建文件夹。
    • boolean mkdirs():创建多层文件夹。
  2. 删除:
    • boolean delete(): 删除失败返回false.
    • void deleteOnExit():在程序退出时删除指定文件。
  3. 判断:
    • booelean canExecute():判断文件是否可执行。
    • boolean exists(): 判断文件或目录是否存在。
    • boolean isFile():判断是否是文件。
    • boolean isDirectory():判断是否是目录。
    • 在判断文件对象是否是文件或者是目录时,必须要先判断该文件对象封装的内容是否存在。通过exists判断。
    • boolean isHidden():判断是否是隐藏文件。
    • boolean isAbsolute():判断是否是绝对路径。
  4. 获取信息:
    • String getName():获取文件名。
    • String getPath():获取文件相对路径。
    • String getParent():获取文件父目录。该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。如果相对路径中有上一层目录,那么该目录就是返回结果。
    • File getAbsoluteFile():获取文件绝对路径并将其封装成对象。
    • String getAbsolutePath():获取文件绝对路径。
    • long lastModified():获取文件最后一次修改时间。
    • long length(): 获取文件大小。
    • File.pathSeparator:返回当前系统默认的路径分隔符,windows默认为 “;”。
    • File.Separator:返回当前系统默认的目录分隔符,windows默认为 “\”。
  5. 重命名:
    • boolean renameTo():将文件重命名,并转移到制定目录下。
  • 获取计算机的盘符:
    File[] files = File.listRoots();
    for (File f:files){
    System.out.println(f);
    }
  • String[] list()方法:
    • 当list方法所属对象是文件时而不是目录时,返回数组为null,调用list方法的File对象必须是封装的一个目录,而且该目录必须存在。
      例如:获取C盘下当前所有的文件夹以及文件的名称(包含隐藏文件)。
      File f = new File("c:\\");
      //File f = new File("c:\\abc.java");
      String[] names = f.list();
      for (String name:names){
      System.out.println(name);
      }
  • String[] list(FileNameFilter,filter)
    • 返回满足过滤器的文件或目录。 
    • 文件过滤器 FileNameFilter 接口,接口中只有一个返回值为boolean 型的accept()方法。
      例如:用匿名内部类的方式来进行文件过滤:返回E盘下mp3文件:
      File dir = new File("E:\\");
      String[] arr = dir.list(new FilenameFilter()
      {
      public boolean accept(File dir,String name)
      {
      return name.endsWith(".mp3");
      }
      });
      //E盘下文件。 
      System.out.println("len:"+arr.length);
      for (String name: arr){
      System.out.println(name);
      }             
      注:list()方法 只返回当前文件目录下的文件及目录的名称。
  • File[] listFiles() 
    • 返回当前目录下的文件以及文件夹的对象。
      例如:获取当前目录下的文件及文件夹名称及长度。
      File dir = new File("E:\\");
      File[] files = dir.listFiles();
      for (File f : files){
      System.out.println(f.getName() +"::"+f.length());
    • File[] listFiles(FileNameFilter,filter)返回满足过滤器的文件或目录。
练习:删除一个带内容的目录
删除原理:在Windows中,删除目录从里面往外删除的。既然是从里往外删除,就需要用到递归。
注:在删除系统盘时,有些是删不掉的。因为有些隐藏目录Java无法访问。无法访问就导致返回数组为空,会出现空指针异常。
系统中有些文件看上去是文件实际是目录,看上去是目录实际上是文件。没有扩展名,会出现空指针异常,导致程序停止。
import java.io.*;
class  RemoveDir
{
	public static void main(String[] args) 
	{
		File dir = new File("H:\\Exercise");
		removeDir(dir);
	}

	public static void removeDir(File 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::"+dir.delete());
	}
}
 
四、递归
  • 什么是递归:
    • 当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。
    • 简单说:功能内部又用到该功能,但是传递的参数值不确定。(每次功能参与运算的未知内容不确定)。
    • 其实递归就是在栈内存中不断的加载同一个函数。
  • 递归的注意事项:
    1. 一定要定义递归的条件。限定条件,程序必须能够结束。
    2. 递归的次数不要过多。容易出现 StackOverflowError 栈内存溢出错误。
    • 原因:当调用函数时会在栈内存中开辟空间,如果调用的次数过多,函数在栈内存中创建的空间就越大,函数没有执行结束,内存空间得不到释放,导致内存溢出。
练习:
import java.io.*;
class FileDemo3 
{
	public static void main(String[] args) 
	{
		File dir = new File("G:\\360Downloads");
		showDir(dir);
		toBin(8);
		int n = getSum(10);
		System.out.println("n = "+ n);
	}
	//输出目录下所有文件夹及文件 
	public static void showDir(File dir)
	{
		System.out.println(dir);
		File[] files = dir.listFiles();
		for (int x = 0;x < files.length;x++)
		{
			if(files[x].isDirectory())
				showDir(files[x]);
			else
				System.out.println(files[x]);
		}
	}
	//求一个整数的2进制 
	public static void toBin(int num)
	{
		/*
		while (num>0)
		{
		System.out.println(num%2);
		num = num / 2;
		}
		*/
		if (num>0)
		{
			toBin(num/2);
			System.out.println(num%2);
		}
	}

	public static int getSum(int n)
	{
		//递归求和
		if (n==1)
		return 1;
		return n+getSum(n-1);
	}
}

第二讲 Properties类

一、简述
      Properties类是Hashtable的子类。也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串,不需要泛型。是集合中和IO技术相结合的集合容器。
  • 特点:
    • 一般用于键值对形式的配置文件。
    • 在加载数据时,需要数据有固定格式:键=值。
    • 可以持久化存储数据。
二、特有方法
  1. 设置
    • Object setProperty(String key,String value);
    • 设置键和值,调用Hashtable的方法put
  2. 获取
    • String getProperty(String key)         指定key搜索value
    • Set<String> stringPropertyName()   返回属性列表的键集,存入Set集合
  3. 加载流和存入流
    1. void load(InputStream ism) 从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
    2. void load(Readerreader)    从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
    3. void list(PrintStream out)    将属性列表输出到指定的输出流
    4. void store(OutputStreamout,String comments) 对应load(InputStream )  将属性列表(键值对)写入输出流。comments属性列表的描述。
    5. void store(Writerwriter, String comments);  对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。
练习: 用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。
/* 
练习:用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。 
     
分析: 
很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在并进行了自增。可是随着该应用程序的退出,
该计数器也在内存中消失了。下一次再启动该程序,又重新开始从0记数。这样不是我们想要的。
程序即使结束,该计数器的值也存在。下一次程序启动后会先加载该计数器的值并加1后再重新存储起来。
所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式。这样便于阅读数据,并操作数据。
键值对数据是map集合。数据是以文件形式存储,使用IO技术。那么map+IO -->Properties。

思路:1、用读取流关联文本信息文件。如果存在则读取,如果不存在,则创建 
      2、每次运行,将文件数据存入集合中,读取值,判断次数,如果小于等于5次,则次数增加1次,如果大于则输出提示信息。 
      3、将值小于等于5次的信息数据存入文件中 
*/ 
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("count.ini");
		//将流中的数据加载进集合。
		prop.load(fis);
		//用于记录程序运行次数
		int count = 0;
		//根据键获取值 
		String value = prop.getProperty("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,"setTime");
		//关闭流资源
				  fos.close();
		fis.close();
	}
}
 
第三讲 其他流
一、打印流
  • 打印流:
    • 包括PrintStream PrintWriter
    • 该流提供了特有的打印方法,可以将各种数据类型的数据都原样打印。 
  • 字节打印流:PrintStream
  • 构造函数可以接受的参数类型:
    1. File对象,File。
    2. 字符串路径,String.
    3. 自节输出流,OutputStream。
  • 字符打印流:PrintWriter
  • 构造函数可以接受的参数类型:
    1. file对象,File。
    2. 字符串路径,String.
    3. 自节输出流,OutputStream。
    4. 字符输出流,Writer。
    • 注:PrintWriter(OutputStream out,boolean autoFlush),autoFlush,如果为true,println、printf或format方法将刷新缓冲区。
练习:
  
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(System.out); 
		// 创建打印流对象,指定目文件相关联,并加入缓冲技术
		PrintWriter out =
			new PrintWriter(new BufferedWriter(new FileWriter("a.txt")),true);
		String line = null;
		while ((line = bufr.readLine())!=null)
		{
			if("over".equals(line))
				break; 
			//将数据写入缓冲区
			//out.write(line);
			//将数据从缓冲区刷新到目的地
			//out.flush(); 
			// 将数据写入缓冲区,从缓冲区刷新到目的地
			out.println(line);
		}
		//关闭流 
		out.close();
		bufr.close();
	}
}
异常日志
      在程序使用过程当中,程序出现问题是不希望打印给用户看到的,因此,创建程序的异常日志,将出现的问题存储,方便程序员对程序进行修改。
示例:
import java.io.*;
import java.util.*;
import java.text.*;

class  ExceptionInfo
{
	public static void main(String[] args) throws IOException
	{
		try
		{
			int[] arr = new int[2];
			System.out.println(arr[3]);
		}
		catch (Exception e)
		{
			try
			{
				//创建时间对象 
				Date date = new Date();
				//将时间格式化 
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
				String s =sdf.format(date);
				//创建输出对象与文件相关联 
				PrintStream ps = new PrintStream("exception.log");
				//输出异常发生时间
				ps.println(s);
				//设置输出设备为文件 
				System.setOut(ps);
			}
			catch (Exception ex)
			{
				throw new RuntimeException("日志文件创建失败");
			}
			e.printStackTrace(System.out);
		}
	}
}
 
获取系统信息

步骤:
  1. 创建Properties对象,接收System类的getProperties()获取的系统信息。
  2. 将信息输出到指定输出流中 
    • 用Properties对象的list(PrintStream out)
  3. 将输出流中数据存入指定文件中
    • new PrintStream("sysout.txt")
import java.util.*;
import java.io.*;
class  SystemInfo
{
	public static void main(String[] args) throws IOException
	{
		Properties prop = System.getProperties();
		//将系统信息输出在控制台 
		//System.out.println(prop);
		//prop.list(System.out);
		//将系统属性信息存储到关联文件中 
		prop.list(new PrintStream("sysout.txt"));
	}
}
 
二、 序列流 (SequenceInputStream)
  • 作用:对多个流进行合并。
  • 构造函数:
    • SequenceInputStream(InputStream s1,InputStream s2)
    • SequenceInputStream(Enumeration<? extends InputStream> e) 
  • 常见合并多个流文件步骤
    1. 创建集合,并将流对象添加进集合
    2. 创建Enumeration对象,将集合元素加入。
    3. 创建SequenceInputStream对象,合并流对象
    4. 创建写入流对象,FileOutputStream关联写入文件
    5. 利用SequenceInputStream对象和FileOutputStream对象读数据进行反复读写操作。
/*
练习:合并多个.txt文件  
*/
import java.io.*;
import java.util.*;
class SequenceDemo 
{
	public static void main(String[] args) throws IOException
	{
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		v.add(new FileInputStream("E:\\1.txt"));
		v.add(new FileInputStream("E:\\2.txt"));
		v.add(new FileInputStream("E:\\3.txt"));
		Enumeration<FileInputStream> en = v.elements();
		//创建序列流对象接收Enumeration对象
		SequenceInputStream sis = new SequenceInputStream(en);
		//创建输出流对象与文件相关联
		FileOutputStream fos = new FileOutputStream("E:\\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();
	}
}

练习:文件的切割与合并
import java.io.*;
import java.util.*;
class SplitMergeFile 
{
	public static void main(String[] args) throws IOException
	{
		//splitFile();
		merge();
	}
    //切割 
	public static void splitFile()throws IOException 
	{ 
		//创建读取流流对象与文件相关联
		FileInputStream fis = new FileInputStream("E:\\1.bmp");
		//创建写入流对象
		FileOutputStream fos = null;
		//创建缓冲区 
		byte[] buf = new byte[1024*1024];
		int len = 0;
		//对切割次数进行标记 
		int count = 1;
		//将切割缓冲区数据读取并写入目的地 
		while ((len = fis.read(buf))!=-1)
		{
			fos = new FileOutputStream("E:\\splitfiles\\"+(count++)+".part");
			fos.write(buf,0,len);
			fos.close();
		}
		fis.close();
	} 
	//合并
	public static void merge()throws IOException
	{
		//创建集合对象
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream> ();
		//创建流对象与文件相关联并将流对象添加到集合中 
		for (int x = 1;x<=3 ;x++)
		{
			al.add(new FileInputStream("E:\\splitfiles\\"+ x +".part"));
		}
		//创建迭代器 
		final Iterator<FileInputStream> it = al.iterator();
		//枚举的匿名内部类来实现迭代 
		Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
		{
			//复写 Enumeration方法
			public boolean hasMoreElements()
			{
				return it.hasNext();
			}
			public FileInputStream nextElement()
			{
				return it.next();
			}
		};
		//c创建序列流对象接收Enumeration对象 
		SequenceInputStream sis = new SequenceInputStream(en);
		//创建输出流对象与文件相关联 
		FileOutputStream fos = new FileOutputStream("E:\\splitfiles\\0.bmp");
		//创建缓冲区 
		byte[] buf = new byte[1024*1024];
		int len = 0;
		while ((len = sis.read(buf))!= -1)
		{ 
			//将缓冲区读取的数据写到目的地
			fos.write(buf,0,len);
		}
		//关闭流资源
		fos.close();
		sis.close();
	}
}
 
三、对象的序列化:
  • 对象的持久化存储(序列化)
    • 对象本身存在于堆内存中,当程序结束后,内存中的垃圾回收,对象也就消失了。
    • 用流将对内存中的对象存储在硬盘上,叫做对象的持久化存储。使用到的类:ObjectInputStream,ObjectOutputStream。
    • 被操作的对象需要实现Serializable接口。
  • 目的:将一个具体的对象进行持久化,写入到硬盘上。
  • 注:
    • 对象中静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
    • 用transient关键字修饰变量,可以让非静态数据不被序列化。
  • Serializable接口:
    • 用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。
    • 这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的。
    • 如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号。
      • "serialVersionUID"的字段(该字段必须是静态 (static)、最终 (final) long 型字段)。
      • 如: public static final long serialVersionUID = 42L;
    • 依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。
  • 写入流对象:
    • 创建对象写入流,与文件关联,即传入目的。
    • 通过写入writeObject(Object obj)方法,将对象作为参数传入,即可写入文件。
  • 读取流对象
    • 创建对象读取流,与文件关联,即传入源。
    • 通过readObject()方法,读取文件中的对象,并返回这个对象。
/* 
需求:将一个对象序列号,并从硬盘中读取序列化的对象 
*/ 
import java.io.*;
public class ObjectStreamDemo {
	public static void main(String[] args) {
		writeObj();
		readObj() ;
	}
	//将指定对象序列化到指定文件中 
	public static void writeObj()
	{
		ObjectOutputStream oos =null;
		try {
			//将一个对象写到文件当中,
			//数据不是纯文本,对文件进行操作
			//选择FileOutputStream
			oos = new ObjectOutputStream(new FileOutputStream("person.object"));
			//数据("lisi",29) 在堆内存中 被封装到Person对象中,
			//将Person对象写入到文件"obj.txt"中
			oos.writeObject(new Person("lisi",29,"kr"));
		} catch (Exception e) {
			throw new RuntimeException("写入数据失败");
		}
		finally{
			try {
				if(oos!=null)
					oos.close();
			} catch (IOException e) {
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
	//读取指定文件中的对象,也称反序列化  
	public static void readObj() 
	{
		ObjectInputStream ois =null;
		try {
			//创建读取流对象,关联文件  
			ois = new ObjectInputStream(new FileInputStream("person.object"));
			 //读取文件中的对象 
			Person p = (Person)ois.readObject();
			System.out.println(p.getName()+":"+p.getAge()+":"+p.getCountry());
		} catch (Exception e) {
			throw new RuntimeException("读取数据失败");
		}
		finally{
			try {
				if(ois!=null)
					ois.close();
			} catch (IOException e) {
				throw new RuntimeException("读取关闭失败");
			}
		}
	}
}
//创建Peason类,实现Serializable接口 
class Person implements Serializable
{
	//自定义serialVersionUID版本号
	private static final long serialVersionUID = 42L;
	private String name;
	transient int age;//用transient修饰后age将不会进行序列化
	static String country ="cn";//静态数据不会进行序列化 
	Person(String name,int age,String country)
	{
		this.name = name;
		this.age = age;
		this. country= country;
	}
	public String getName() {
		return name + ":" + age +","+id+","+ country;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public static String getCountry() {
		return country;
	}
	public static void setCountry(String country) {
		Person.country = country;
	} 
} 
四、管道流:
  • 管道流:PipedInputStream。PipedOutputStream。
  • 特点:
    • 输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。connect()方法,链接管道输入流和管道读取流。
    • 通过结合线程使用。管道读取流可以读取管道写入流写入的数据。
    • 注:因为read方法是阻塞式的,没有数据的read方法会让线程等待。使用单线程,先执行read,会发生死锁,所以需要使用多线程技术。
    • 通常,数据由某个线程写入PipedOutputStream对象,并由其他线程从连接的 PipedInputStream 读取。
  • 一般操作步骤:
    1. 要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常。
    2. 创建两个管道流,并用connect()方法将两个流连接
    3. 创建读写对象,并传入两个线程内,并start执行。
练习:
import java.io.*;
class Read implements Runnable
{
	private PipedInputStream in;
	Read(PipedInputStream in)
	{
		this.in = in;
	}
	public void run()//覆盖run方法。异常不能抛,只能try。
	{
		try
		{
			byte[] buf = new byte[1024];
			System.out.println("读取前..没有数据,阻塞");
			//阻塞式方法read,没有数据就得等,等些入数据后才执行。
			int len = in.read(buf);
			System.out.println("读到数据..阻塞结束");
			String s = new String(buf,0,len);
			System.out.println(s);
			in.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道读取流失败");
		}
	}
}

class Write implements Runnable
{
	private PipedOutputStream out;
	Write(PipedOutputStream out)
	{
		this.out = out;
	}
	public void run()
	{
		try
		{
			System.out.println("开始写入数据,等待6秒后.");
			Thread.sleep(3000);
			out.write("piped lai la".getBytes());
			out.close();
		}
		catch (Exception e )
		{
			throw new RuntimeException("管道输出流失败");
		}
	}
}

class  PipedStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream();
		in.connect(out);
		Read r = new Read(in);
		Write w = new Write(out);
		new Thread(r).start();
		new Thread(w).start();
	}
}
五、RandomAccessFile类
  • 作用:可以实现数据的分段写入。(下载软件原理,多线程下载)
  • 该类不算是IO体系中子类,而是直接继承自Object。但是它是IO包中成员。因为它具备读和写的功能。
  • 特点: 
    1. 该对象既可以读取,也可以写入。 
    2. 对象内部封装了一个byte数组,而且通过指针对数组的元素进行操作。,
    3. 该对象可以通过getFilePointer()方法获取指针位置。同时可以通过seek()方法改变指针的位置。
    4. 该对象操作的源和目的必须是文件。
    5. 该对象内部封装了字节输入流和字节输出流。
  • 完成读写原理:
    • 内部封装了字节输入流和字节输出流。byte数组操作的是字节。
    • 通过构造函数可以看出,该类只能操作文件。
    • 而且操作文件还有模式:只读r,读写rw等。,
    • 如果模式为只读 r 。不会创建文件,会去读取一个已存在的文件。
    • 如果该文件不存在,则会出现异常。
    • 如果模式为rw。操作的文件不存在,会自动创建,如果存在则不会覆盖。
  • 随机访问文件,自身具备读写的方法。
    • 通过skipBytes(int x),seek(int x);来达到随机访问。
    • skipBytes(int x),调整对象中指针,只能向后,不能向前。
    • seek(int x) 调整对象中指针,可以前后移动。
  • 注:在实现随机数据读取时,数据最好有规律。
练习:
import java.io.*;
class  RandomAccessFileDemo
{
	public static void main(String[] args) throws IOException
	{
		writeFile();
		readFile();
	}
	public static void readFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
		//调整对象中指针。分段要有规律
		//raf.seek(8*1);
		//跳过指针的字节数。
		raf.skipBytes(8);
		byte[] buf = new byte[4];
		raf.read(buf);
		String name = new String(buf);
		int age = raf.readInt();
		System.out.println("name:"+name);
		System.out.println("age = "+age);
		raf.close();
	}
	public static void writeFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
		raf.write("张三".getBytes());
		//write方法只写出int类型的最低8位。
		raf.writeInt(99);
		raf.write("李四".getBytes());
		raf.writeInt(97);
		raf.close();
	}
	//在文件随机位置写入数据
	public static void writeFile_2()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
		raf.seek(8*3);
		raf.write("周七".getBytes());
		raf.writeInt(103);
		raf.close();
	}
}

 六、操作基本数据类型的流对象

  • 操作基本数据类型的流对象:DataInputStreamDataOutputStream
  • 可用于操作基本数据类型的流对象,包含读写各种基本数据类型的方法。

DataOutputStream  dos = new DataOutputStream(new FileOutputStream("data.txt"));

dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9867.453);
dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println("num =" +num);
System.out.println("b =" + b);
System.out.println("d =" + d);
dis.close();

  • 注:
    • String readUTF();//对应writeUTF,读取以UTF-8修改版编码写入的字符串
    • writeUTF(String str);//以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。


七、 操作字节数组的流对象。
  • 操作字节数组的流:ByteArrayInputStreamByteArrayOutputStream
  • ByteArrayInputStream:  在构造的时候,需要接收数据源,而且数据源是一个字节数组。
  • ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经封装了一个可变长度的字节数组。这就是数据目的地。
  • 因为这两个流对象操作的都是数组并没有使用系统资源,所以不用进行close关闭。即使关闭后,仍可调用。
  • 内部包含缓冲区,相当于以内存作为流操作源和目的,不会产生任何IO异常。
  • 对象中封装了数组。 
  • 特有方法:
    • ByteArrayOutputStream中:
    • writeTo(OutputStream out);
      • 将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用out.write(buf, 0, count)调用该输出流的 write 方法效果一样。
      • 因为这个方法用到了字节输出流,需要抛IO异常,也是字节数组流中唯一需要抛异常的方法。
    • int size();//当前缓冲区的大小
    • String toString();使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。
  • 对应的字符数组和字符串
    • 字符数组流:CharArrayReaderCharArrayWriter
    • 字符串流:   StringReaderStringWriter
import java.io.*;

class  ByteArrayStream
{
	public static void main(String[] args) 
	{
		//System.out.println("Hello World!");
		//数据源。
		ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".getBytes());
		// 数据目的
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		int by = 0;
		while ((by = bis.read())!= -1)
		{
			bos.write(by);
		}
		System.out.println(bos.size());
		System.out.println(bos.toString());
		//bos.writeTo(new FileOutputStream("a.txt"));
	}
}



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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值