Java IO基础

本文围绕Java的IO流展开,介绍了IO对文件与文件夹的基本操作,如使用File类进行增删查。还提及RandomAccessFile,不过一般用字节流或字符流操作。详细阐述了字节流和字符流的基本操作、区别,指出开发中字节流使用更广泛,并说明了字节与字符流在文件复制中的选择与应用。

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

IO流操作请多参考JDK文档https://docs.oracle.com/javase/8/docs/api/

1、IO对文件与文件夹的基本操作(增删查 )。(改文件/夹的名/内容留着后面分析)

在Java中使用File类表示文件本身,可以直接使用此类完成文件的各种操作,如创建、删除等。
File类的常用方法和常量讲解:

构造方法方法或常量类型描述
public static final String pathSeparator常量与系统相关的路径分隔符字符,为方便表示字符串
public static final String separator常量与系统相关的默认名称 - 分隔符字符符串
public File(String pathname)构造方法通过将给定的路径名字符串转换为抽象路径名来创建新的File实例。 如果给定的字符串是空字符串,则结果是空的抽象路径名

pathSeparator 和separator作为常量未大写是因为在File类出现前Java还未对命名进行规范。这可能就叫做历史遗憾吧。

方法使用:

  • File(String pathname),通过将给定的路径名字符串转换为抽象路径名,来创建新的 File实例。
  • public boolean delete(),删除由此抽象路径名表示的文件或目录。 如果此路径名表示目录,则目录必须为空才能删除。
  • public boolean exists(),测试此抽象路径名表示的文件或目录是否存在。
  • public boolean mkdir(),创建由此抽象路径名命名的目录。
  • public String[] list(),列出全部名称,返回一个字符串数组
  • public File[] listFiles(),列出全部的路径,返回一个File对象数组。
  • public boolean isDirectory(),测试此抽象路径名表示的文件是否为目录。
public class FileDemo01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//1、给出完整路径
		//使用File.separator能表示自己系统目录分割符,如Windows中为“\”
		String  folderPath="F:"+File.separator+"IO";
		String filePath=folderPath+File.separator+"text.txt";
		//创建文件夹与文件
		File folder=new File(folderPath);
		createFolder(folder);
		File file=new File(filePath);
		createFile(file);
		//列出文件与文件夹
		list(file,folder);
	}
	//创建文件夹
	static void createFolder(File folder) {
		//创建文件夹
		folder.mkdir();
	}
	//创建文件
	static void createFile(File file) {
		//2、判断文件是否存在
		if(file.exists()) {
			//如果文件存在,删除
			file.delete();
		}else {
			try {
				//如果文件不存在,根据给出的路径创建新文件
				file.createNewFile();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	//列出文件夹的内容与目录
	static void list(File file,File folder) {
		//判断是否是目录
		if(folder.isDirectory()) {
			System.out.println(folder.getPath()+"路径是目录");
			System.out.println("--------------");
			//如果目录不为空并且文件存在
			if(folder!=null&&file.exists()) {
				String list[]=folder.list();
				File listFiles[]=folder.listFiles();
				for (int i = 0; i < list.length; i++) {
					//获取文件夹路径并列出文件名称
					System.out.println(folder.getPath()+"文件夹中有:"+list[i]+"文件");
				}
				for (int i = 0; i < listFiles.length; i++) {
					//获取文件夹路径并列出文件路径
					System.out.println(folder.getPath()+"文件夹中文件路径为:"+listFiles[i]);
				}
			}else if((!file.exists())&&folder!=null){
				System.out.println(folder.getPath()+"文件夹中没有内容!");
			}
		}else {
			System.out.println(folder.getPath()+"文件夹不存在");

		}
		
	}
}

运行结果:

F:\IO路径是目录
--------------
F:\IO文件夹中有:text.txt文件
F:\IO文件夹中文件路径为:F:\IO\text.txt

2、RandomAccessFile

RandomAccessFile可以从指定位置开始读取信息,但是要求文件中各个数据保存长度必须固定,并且通过随机读写流实现文件内容的操作会过于复杂。一般使用字节流或字符流进行操作。知道有他就行了。

3、字节流与字符流基本操作

内存读取存储介质数据叫输入流,内存写入存储介质叫输出流。

  • 1、字节流
    字节流主要操作byte类型数据,以byte数据为准,主要操作类为字节输出流OutputStream类和字节输入流InputStream类。
    • .1.1 输出流OutputStream:
      public abstract class OutputStream extends Object implements Closeable, Flushable,这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。因此我们需要OutputStream子类来实例化它。
      常用子类之一
      public FileOutputStream(File file) throws FileNotFoundException {}
      public FileOutputStream(File file, boolean append) throws FileNotFoundException{}
public class OutputStreamDemo01 {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		String filePath="F:"+File.separator+"IO"+File.separator+"text.txt";
		//创建文件
		File file=new File(filePath);
		//实例化OutputStream,并且可以在文件后面追加内容
		OutputStream out=new FileOutputStream(file,true);
		String str1="Hello write(byte[] b)";
		//使用"\r\n"可以增加换行
		String str2 = "\r\n Hello write(int t)";
		//将字符串变为byte数组
		byte[] b1=str1.getBytes();
		byte[] b2=str2.getBytes();
		//方法一、将byte数组写入数据流
		out.write(b1);
		//方法二、使用write(int t)将字节一个一个得输出到文件中
	    for (int i = 0; i < b2.length; i++) {
			out.write(b2);
		}
		//关闭输出流
		out.close();
	}

}
  • 1.2 输入流InputStream:
    public abstract class InputStream implements Closeable
    这个抽象类是表示输入字节流的所有类的超类。需要定义InputStream子类的应用InputStream必须始终提供一种返回输入的下一个字节的方法。
    常用子类:FileInputStream(File file)
    • A当知道文件大小
      a、直接从文件中读取内容
public class InputStreamDemo01 {
    	public static void main(String[] args) throws Exception {
    		// TODO Auto-generated method stub
    		String filePath="F:"+File.separator+"IO"+File.separator+"text.txt";
    		//创建文件
    		File file=new File(filePath);
    		//实例化InputStream
    		InputStream in=new FileInputStream(file);
    		//将所有内容读到此数组中
    		byte[] b=new byte[666];
    		//把内容取出,内容读到数组中
    		in.read(b);
    		//关闭输入流
    		in.close();
    		//将byte数组变为字符串输出
    		System.out.println("内容为:"+new String(b));
    	}
    }

结果:

内容为:Hello write(byte[] b)
Hello write(int t)(很多空格......)

public int read(byte[] b) throws IOException
从该输入流读取高达byte.length字节的数据到字节数组。
直接通过read()读取文件,会将数组内容全部读出来,即使数组被内容大很多

b、将byte指定范围内容变为字符串输出

       byte[] b=new byte[666];
       //把内容取出,内容读到数组中
		int len=in.read(b);
		//关闭输入流
		in.close();
		//数组的长度
		System.out.println("读出数据的长度:"+len);
		//将byte数组变为字符串输出
		System.out.println("内容为:"+new String(b,0,len));

平台上显示的内容为数组中实际的文字或数组内容,无多余空格

c、开辟指定大小的byte数组

       //实例化InputStream
		InputStream in=new FileInputStream(file);
		//进行读操作,获取文件大小
		//数组大小由文件决定
		byte[] b=new byte[(int)file.length()];
		//把内容取出,内容读到数组中
		in.read(b);
		//关闭输入流
		in.close();
		//将byte数组变为字符串输出
		System.out.println("内容为:"+new String(b));

File类中的public long length()
返回由此抽象路径名表示的文件的长度。 如果此路径名表示目录,则返回值未指定。
通过length()方法可以获取文件的长度,能避免因不知道文件大小而造成大数组装小内容的资源浪费。
d、使用read()循环读取
能解决不知道数组大小的问题

        //实例化InputStream
		InputStream in=new FileInputStream(file);
		//进行读操作
		byte[] b=new byte[(int)file.length()];
		//将文件内容依次读入数组
		for (int i = 0; i < b.length; i++) {
			b[i]=(byte) in.read();
		}
		//关闭输入流
		in.close();
		//将byte数组变为字符串输出
		System.out.println("内容为:"+new String(b));

public int read() throws IOException
从该输入流读取下一个数据字节, 值字节作为int返回为0到255 。

  • B当不知道文件大小
//实例化InputStream
		InputStream in=new FileInputStream(file);
		//进行读操作
		byte[] b=new byte[666];
		int len=0;//记录读取的数据的个数
		int temp=0;//接收读取的每一个数据
		//将每次读取的数据内容给temp变量,如果temp变量值不为-1,表示文件没有读完
		while((temp=(in.read()))!=-1) {
			b[len]=(byte)temp;
			len++;
		}
		//关闭输入流
		in.close();
		//将byte数组变为字符串输出
		System.out.println("内容为:"+new String(b,0,len));

文件读到末尾了,则返回的内容为-1

  • 2、字符流
  • 2.1字符输出流Writer
    public abstract class Writer extends Object implements Appendable, Closeable, Flushable
    其中的Appendable接口表示文件内容可以被追加,接收的参数事CharSequence,实际上String类也实现了此接口,所有可以直接通过此接口的方法向输出流中追加内容。
    FileWriter类的构造方法:
    public FileWriter(String fileName) throws IOException
  • a、向文件中写内容
        File file=new File(path);
        //通过子类实例化接口
		Writer out=new FileWriter(file);
		String str="Hello Writer()方法";
		//字符输出
		out.write(str);
		out.close();

程序操作与OutputStream的操作流程相比,唯一的好好处是可以直接输出字符串不用将字符串变为byte数组后输出。

  • b、向文件中追加内容
    通过public FileWriter(String fileName,boolean append) throws IOException
    构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。
File file=new File(path);
		Writer out=new FileWriter(file,true);
		String str="\r追加Hello Writer()方法";
		out.write(str);
		out.close();
  • 2.2 字符输入流Reader
  • a、从文件中读取内容
File file=new File(path);
		//实例化接口
		Reader input=new FileReader(file);
		//读取文件内容
		char[] c=new char[666];
		//public int read(char[] cbuf) throws IOException
		//将内容读到字符数组中,返回读入的长度。
		int len=input.read(c);
		input.close();
		//将数组变为字符串输出
		System.out.println(new String(c,0,len));

结果:

Hello Writer()方法
追加Hello Writer()方法
  • b、使用循环方式读取内容
    在不知道数组的大小的时候,使用循环的方式读取文件内容
File file=new File(path);
		//实例化接口
		Reader input=new FileReader(file);
		//读取文件内容
		char[] c=new char[666];
		int len=0;//记录读取到的数据个数
		int temp=0;//将数组读入到temp中
		//使用read()读取单个字符
		while((temp=input.read())!=-1) {
			c[len]=(char)temp;
			len++;
		}
		input.close();
		//将数组变为字符串输出
		System.out.println("数组长度为:"+len);
		System.out.println(new String(c,0,len));

4、字节流与字符流区别

1、代码上的区别(见上面)
2、操作的区别
在这里插入图片描述
字节流在操作是本身不会使用到缓冲区(内存),是文件本身直接操作。而字符流在操作时使用了缓冲区,通过缓冲区在操作文件。
在关闭字符流时会强制将缓冲区的内容进行输出,如果程序没有关闭则缓存区内容不能输出,内容无法写进文件。

  • 2.1使用字节流不关闭执行
        //创建文件
		File file=new File(filePath);
		//实例化OutputStream,并且可以在文件后面追加内容
		OutputStream out=new FileOutputStream(file);
		String str="字符流与字节流的操作区别——字符流要使用缓存";
		char[] c=new char[666];
		byte[] b=str.getBytes();
		out.write(b);
		//不关闭输出流

在使用字节流直接进行输出操作时,未关闭输出流,内容仍然写入文件。

  • 2.2 使用字符流不关闭操作
//创建文件
		File file=new File(filePath);
		//实例化OutputStream,并且可以在文件后面追加内容
		Writer writer=new FileWriter(file);
		String str="字符流与字节流的操作区别——字符流要使用缓存";
		char[] c=new char[666];
		writer.write(str);
		//不关闭输出流

未关闭字符流,内容也未成功写入文件
2.3 强制性清空缓存
使用flush()可以清空缓冲区,也就能强制性将内容存到文件中。

//创建文件
		File file=new File(filePath);
		//实例化OutputStream,并且可以在文件后面追加内容
		Writer writer=new FileWriter(file);
		String str="字符流与字节流的操作区别——字符流要使用缓存";
		char[] c=new char[666];
		writer.write(str);
		writer.flush();
		//不关闭输出流

通过上面代码证明了字符流输出操作需要缓冲区,字节操作不使用缓冲区
3、开发中,字节流使用更广泛
所有的文件在硬盘或传输时都是以字节的方式存在的,包括图片等也是以字节的方式存储的,而字符是只有在内存中才会形成。

5、字节与字符的选择与应用

需求:进行文件的复制。
分析1:复制文件必须要由源文件与目标文件两个,而且输入的源文件路径还需存在。如果不满足上面两个条件就给出错误提示。
分析2:复制的文件内容不仅仅是文字还可能需要复制图片,这时就需要使用字节流。
分析3:复制文件有两种方式:
1、将源文件内容读取到缓冲区,再一次性写入目标文件。
如果源文件内容过大可能出现缓冲区装不下,放弃。
2、不将源文件全部读取出来,而且边读边写。

public class Copy {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//如果文件名不足2个,给出错误提示
		if(args.length!=2) {
			System.out.println("输入的参数不正确");
			System.out.println("如 copy 源文件路径  目标文件路径");
			//退出System.exit()方法中非0就行;
			System.exit(1);
		}
		//源文件对象
		File y=new File(args[0]);
		//目标文件路径
		File m=new File(args[1]);
		//如果源文件路径不存在,提示错误
		if(!y.exists()) {
			System.out.println("源文件路径不正确,请重新输入");
			System.exit(1);
		}
		//文件输入流
		InputStream input=null;
		try {
			input=new FileInputStream(y);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//文件输出流
		OutputStream out=null;
		try {
			out=new FileOutputStream(m);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//确保输入流与输出流已经实例化,准备就绪
		if(input!=null&&out!=null) {
			//判断文件是否读取结束
			int temp=0;//存每个字节
			try {
				//读取每一个字节
				while((temp=input.read())!=-1) {
					//实现边读边写操作
					out.write(temp);
				}
				System.out.println("复制成功!");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("复制失败!");
			}
		}
		//关闭输入输出流
		try {
			input.close();
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

附:
在Eclipse中向main(String[] args)中的数组添加内容
进入Run——>Run Configurations找到下图所示位置填写内容。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值