黑马程序员——IO的使用

本文详细解析了Java IO流的概念及其分类,包括字节流与字符流,并展示了如何通过File类进行文件系统操作,如创建、读取、删除等。同时介绍了流的读写操作规律和常见异常处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


IO流:用于处理设备上数据。可以理解数据的流动,就是一个数据流。IO流最终要以对象来体现,对象都存在IO包中。

流也进行分类:

1:输入流(读)和输出流(写)。

2:因为处理的数据不同,分为字节流和字符流。

 

字节流:处理字节数据的流对象。设备上的数据无论是图片或者dvd,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。

 

注意:流的操作只有两种:读和写。

流的体系因为功能不同,但是有共性内容,不断抽取,形成继承体系。该体系一共有四个基类,而且都是抽象类。

 字符流:Reader  Writer

字节流:InputStream  OutputStream


字符流:

Reader用于读取字符流的抽象类。子类必须实现的方法只有 read(char[],int, int) 和 close()。

     |---BufferedReader从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

       |---LineNumberReader跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int)getLineNumber(),它们可分别用于设置和获取当前行号。

     |---InputStreamReader是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

       |---FileReader用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。

     |---CharArrayReader

     |---StringReader

-------------------------------------------------

Writer写入字符流的抽象类。子类必须实现的方法仅有 write(char[],int, int)、flush() 和 close()。

     |---BufferedWriter将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

     |---OutputStreamWriter是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

       |---FileWriter用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。

     |---PrintWriter

     |---CharArrayWriter

     |---StringWriter

---------------------------------

字节流:

InputStream是表示字节输入流的所有类的超类。

     |--- FileInputStream从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。FileInputStream用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。

     |--- FilterInputStream包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。

       |--- BufferedInputStream该类实现缓冲的输入流。

       |--- Stream

     |--- ObjectInputStream

     |--- PipedInputStream

-----------------------------------------------

OutputStream此抽象类是表示输出字节流的所有类的超类。

     |--- FileOutputStream文件输出流是用于将数据写入 FileFileDescriptor 的输出流。

     |--- FilterOutputStream此类是过滤输出流的所有类的超类。

       |--- BufferedOutputStream该类实现缓冲的输出流。

       |--- PrintStream

       |--- DataOutputStream

     |--- ObjectOutputStream

     |--- PipedOutputStream

在这四个系统中,它们的子类,都有一个共性特点:子类名后缀都是父类名,前缀名都是这个子类的功能名称。

import java.io.*;
class  FileWriterDemo
{
	public static void main(String[] args) throws IOException
	{
		//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
		//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
		//其实该步就是在明确数据要存放的目的地。
		FileWriter fw = new FileWriter("demo.txt");

		//调用write方法,将字符串写入到流中。
		fw.write("abcde");

		//刷新流对象中的缓冲中的数据。
		//将数据刷到目的地中。
		//fw.flush();


		//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
		//将数据刷到目的地中。
		//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
		fw.close();
	}
}
<p><strong><span style="color:red;">close()</span><span style="color:red;">和</span><span style="color:red;">flush()</span><span style="color:red;">的区别:</span></strong></p><p>flush():将缓冲区的数据刷到目的地中后,流可以使用。</p><p>close():将缓冲区的数据刷到目的地中后,流就关闭了,该方法主要用于结束调用的底层资源。这个动作一定做。</p><p><strong><span style="color:red;">io</span><span style="color:red;">异常的处理方式:</span><span style="color:red;">io</span><span style="color:red;">一定要写</span><span style="color:red;">finally</span><span style="color:red;">;</span></strong></p>

FileWriter写入数据的细节:

1:window中的换行符:\r\n两个符号组成。 linux:\n。

2:续写数据,只要在构造函数中传入新的参数true。

3:目录分割符:window \\  /

public static void main(String[] args) {
		FileWriter fw = null;
		try {
			fw = new FileWriter("demo.txt",true);
			fw.write("abcde");
		}
		catch (IOException e ){
			System.out.println(e.toString()+"....");
		}
		finally{
			if(fw!=null)
				try{
					fw.close();
				}
				catch (IOException e){
					System.out.println("close:"+e.toString());
				}
		}
}
//FileReader:使用Reader体系,读取一个文本文件中的数据。返回 -1 ,标志读到结尾。

另一种读取数据高效率的方法:自定义缓冲区,或者直接使用BufferedReader:java写好的缓冲区类

import java.io.*;
class FileReaderDemo2 {
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("demo.txt"); //创建读取流对象和指定文件关联。
		//因为要使用read(char[])方法,将读取到字符存入数组。所以要创建一个字符数组,一般数组的长度都是1024的整数倍。
		char[] buf = new char[1024];
		int len = 0;
		while(( len=fr.read(buf)) != -1) {
			System.out.println(new String(buf,0,len));
		}
		fr.close();
	}
}

流的操作规律:

1,明确源和目的。

       数据源:就是需要读取,可以使用两个体系:InputStreamReader

       数据汇:就是需要写入,可以使用两个体系:OutputStreamWriter

2,操作的数据是否是纯文本数据?

       如果是:数据源:Reader

                  数据汇:Writer

       如果不是:数据源:InputStream

                    数据汇:OutputStream

3,虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?

       明确操作的数据设备。

       数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)

       数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)

4,需要在基本操作上附加其他功能吗?比如缓冲。

       如果需要就进行装饰。

------------------------------------------------------------------------------------------------------------------------

File类:将文件系统中的文件和文件夹封装成了对象。提供了更多的属性和行为可以对这些文件和文件夹进行操作。这些是流对象办不到的,因为流只操作数据。

 

File类常见方法:

1:创建。

    boolean createNewFile():在指定目录下创建文件,如果该文件已存在,则不创建。而对操作文件的输出流而言,输出流对象已建立,就会创建文件,如果文件已存在,会覆盖。除非续写。

    boolean mkdir():创建此抽象路径名指定的目录。

    boolean mkdirs():创建多级目录。

2:删除。

    boolean delete():删除此抽象路径名表示的文件或目录。

    void deleteOnExit():在虚拟机退出时删除。

注意:在删除文件夹时,必须保证这个文件夹中没有任何内容,才可以将该文件夹用delete删除。

    window的删除动作,是从里往外删。注意:java删除文件不走回收站。要慎用。

3:获取.

    long length():获取文件大小。

    String getName():返回由此抽象路径名表示的文件或目录的名称。

    String getPath():将此抽象路径名转换为一个路径名字符串。

    String getAbsolutePath()返回此抽象路径名的绝对路径名字符串。

    String getParent():返回此抽象路径名父目录的抽象路径名,如果此路径名没有指定父目录,则返回 null

long lastModified():返回此抽象路径名表示的文件最后一次被修改的时间。

File.pathSeparator:返回当前系统默认的路径分隔符,windows默认为 “;”。

File.Separator:返回当前系统默认的目录分隔符,windows默认为 “\”。

4:判断:

    boolean exists()判断文件或者文件夹是否存在。

    boolean isDirectory()测试此抽象路径名表示的文件是否是一个目录。

    boolean isFile()测试此抽象路径名表示的文件是否是一个标准文件。

    boolean isHidden():测试此抽象路径名指定的文件是否是一个隐藏文件。

    boolean isAbsolute():测试此抽象路径名是否为绝对路径名。

5:重命名。

     boolean renameTo(Filedest):可以实现移动的效果。剪切+重命名。

 String[] list()列出指定目录下的当前的文件和文件夹的名称。包含隐藏文件。

如果调用list方法的File 对象中封装的是一个文件,那么list方法返回数组为null。如果封装的对象不存在也会返回null。只有封装的对象存在并且是文件夹时,这个方法才有效。

File[] listFiles()列出指定目录下的当前的文件和文件夹的对象。包含隐藏文件。

------------------------------------------------------------------------------------------------

递归:就是函数自身调用自身。

什么时候用递归呢?

当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。

简单说:功能内部又用到该功能,但是传递的参数值不确定。(每次功能参与运算的未知内容不确定)。

 

递归的注意事项:

1:一定要定义递归的条件。

2:递归的次数不要过多。容易出现 StackOverflowError 栈内存溢出错误

其实递归就是在栈内存中不断的加载同一个函数。


/*
列出指定目录下文件或者文件夹,包含子目录中的内容。
也就是列出指定目录下所有内容。

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

递归要注意:
1,限定条件。

2,要注意递归的次数。尽量避免内存溢出。





*/

import java.io.*;

class FileDemo3 
{
	public static void main(String[] args) 
	{
		File dir = new File("src");
		showDir(dir,0);

	}
	public static String getLevel(int level)
	{
		StringBuilder sb = new StringBuilder();
		sb.append("|--");
		for(int x=0; x<level; x++)
		{
			//sb.append("|--");
			sb.insert(0,"|  ");

		}
		return sb.toString();
	}
	public static void showDir(File dir,int level)
	{
		
		System.out.println(getLevel(level)+dir.getName());

		level++;
		File[] files = dir.listFiles();//列出指定目录下的当前的文件和文件夹的对象
		for(int x=0; x<files.length; x++)
		{
			if(files[x].isDirectory())
				showDir(files[x],level);
			else
				System.out.println(getLevel(level)+files[x]);
		}
	}
	
}

显示结果:

|--src
|  |--src\df.java
|  |--src\FileDemo3.java
|  |--src\SearchFile.java
|  |--src\SystemDemo.java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值