编程语言

园陌·2022/4/16·3 阅读


文件

文件分类

  • 文本文件
    • 文件内容为ascii编码或unicode编码的字符序列
  • 二进制文件
    • 其他非文本文件都可以看做二进制文件,二进制文件在进行处理时,通常是按字节来处理的。
    • 文本文件也可以当做二进制文件处理,但二进制文件通常只按二进制文件而不当做文本文件处理。

File类

  • File以一种系统无关的方式表示一个文件对象的属性。目录在Java中作为一种特殊的文件。此类的实例可能表示(也可能不表示)实际文件系统对象,如文件或目录。
  • File 类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变,这就像String对象一样。
  • File 类封装了对文件系统进行操作的功能。其对象属性包含了文件或目录的相关信息。
  • File类关心的是文件在磁盘上的存储,而不是文件的内容。

名称分隔符

在不同的操作系统中,目录结构中的不同层次的分隔符不同,比如在类Unix操作系统中,文件名的分隔符为/,在Windows系统中,文件名的分隔符为\。由于\同转义符的前导符\相同,我们在java中在表示该符号的时候,我们写作'\\'。 因为Java是跨平台的编程语言,所以在File中定义了两个属性,分别为:public static final String separatorpublic static final char separatorChar,一个是字符串的表示,一个是字符的表示,在Unix系统中分别为:"/"'/',在Windows中为:"\\"'\\',我们在编写程序的时候是不需要关注它的具体值的。

路径分隔符

同样,在不同的操作系统中,路径之间的分隔符也是不同的,在类Unix操作系统中,路径的分隔符为:,在Windows系统,路径的分隔符为;。在File中也定义了两个属性,分别为:public static final String pathSeparatorpublic static final char pathSeparatorChar,同样一个是字符串的表示,一个是字符的表示。

路径的Parent

在Java中,看待路径和文件是统一的,都可以当作File,它的Parent由路径名前缀以及路径名名称序列中的每个名称(最后一个除外)组成,例如:"file://usr/local/bin"的Parent既是"file://usr/local

File的构造方法

  • File(File parent, String child) 根据 parentchild 路径名字符串创建一个新 File 实例。如果 parentnull,则创建一个新的 File 实例,这与调用给定 child 路径名字符串的单参数 File 构造方法的效果一样。如果child 参数为 null,抛出NullPointerException 异常
  • File(String pathname) 通过将给定路径名字符串来创建一个新 File 实例。如果 pathname 参数为 null,抛出NullPointerException 异常
  • File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。如果 parentnull,则创建一个新的File 实例,这与调用给定 child 路径名字符串的单参数 File 构造方法的效果一样。如果child 参数为 null,抛出NullPointerException 异常
  • File(URI uri) 通过将给定的 file: URI 来创建一个新的 File 实例。如果uri参数为 null,抛出NullPointerException 异常,如果关于参数的前提不成立,抛出IllegalArgumentException异常

示例: 例1

String path="d:\\java\\";
File f1=new File(path,"old.txt");

例2

File f1=new File("d:\\java\\old.txt");

例3

String path="d:\\java\\";
File f1=new File(path);
File f2=new File(f1, "old.txt");

File中常用的方法

见JDK说明书

流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件、内存、或是网络连接。凡是从外部设备流向中央处理器CPU的数据流,称为输入流,如图: 类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样,凡是从中央处理器CPU流向外部设备的数据流,称为输出流,如图:

Java流中流动的数据有两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStreamOutputStreamReaderWriter。抽象类InputStreamOutputStream处理字节流;抽象类ReaderWriter处理字符流。Java中其他多种多样变化的流均是由它们派生继承来的。

针对字符流的类基本上都有与之相对应的字节流类。两个对应类实现的功能相似,只是在操作时不同。例如: CharArrayReaderByteArrayInputStream的作用都是把流中的数据读入内存中的一个缓冲区,所不同的是前者是把字符数组作为缓冲区,而后者是把字节数组作为缓冲区。

InputStreamReaderOutputStreamWriter:把字节流转换成一个字符流。

对文件进行读写

与文件的输入输出相关的类有:FileInputStreamFileOutputStreamFileReaderFileWriter,前两个是将文件的内容看作是字节流,后两个将文件看作字符流。

示例1:

/**************************************
*下面的示例将文本文件的内容输出到屏幕 *
**************************************/

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

class ReadFromFile {

	public static void main(String[] args) {
		File file = new File(args[0]);

		try {
			BufferedReader br = new BufferedReader(new FileReader(file));

			String sBuffer;
			try {
				while ((sBuffer = br.readLine()) != null) {
					System.out.println(sBuffer);
				}
			} catch (Exception e) {}
			finally {
				try {
					br.close();
				} catch (Exception e) {

				}
			}
		} catch (Exception e) {

		}


	}

}

示例2:

/********************************************
*下面的示例将键盘中键入的内容存入文本文件中 *
********************************************/

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.BufferedWriter;
import java.io.FileWriter;

class WriteToFile {

	public static void main(String[] args) {
		File file = new File(args[0]);

		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			BufferedWriter bw = new BufferedWriter(new FileWriter(file));

			String sBuffer;
			try {
				while ((sBuffer = br.readLine()) != null) {
					bw.write(sBuffer);
					bw.newLine();
				}
			} catch (Exception e) {}
			finally {
				try {
					br.close();
					bw.close();
				} catch (Exception e) {

				}
			}
		} catch (Exception e) {

		}


	}

}

基本数据的输入输出

数据输入输出流允许应用程序以与机器无关方式读取或写入基本 Java 数据类型,包含两个类:DataInputStreamDataOutputStream

示例1:

/********************************************
*本例将几个基本类型的数据存入文件中         *
********************************************/

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.File;

class WriteDataToFile {
	public static void main(String[] args) {
		File file = new File(args[0]);

		try {
			DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
			try {

				dos.writeBoolean(true);
				dos.writeBoolean(false);
				dos.write(12);
				dos.writeShort(12);
				dos.writeInt(12);
				dos.writeLong(12);
				dos.writeChar('A');
				//dos.writeChars("abc");
				dos.writeFloat(1.2f);
				dos.writeDouble(1.2);
				

			} catch (Exception e) {

			} finally {
				try {
					dos.close();
				} catch (Exception e) {

				}
			}
		} catch (Exception e) {

		}

	}
}

示例2:

/**********************************************
*本例将基本类型的数据从文件中读出并输出到屏幕 *
**********************************************/

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.File;

class ReadDataFromFile {
	public static void main(String[] args) {
		File file = new File(args[0]);

		try {
			DataInputStream dis = new DataInputStream(new FileInputStream(file));
			try {

				System.out.println(dis.readBoolean());
				System.out.println(dis.readBoolean());
				System.out.println(dis.read());
				System.out.println(dis.readShort());
				System.out.println(dis.readInt());
				System.out.println(dis.readLong());
				System.out.println(dis.readChar());
				//System.out.println(dis.readChars());
				System.out.println(dis.readFloat());
				System.out.println(dis.readDouble());
				//System.out.println(dis.readInt());
				

			} catch (Exception e) {

			} finally {
				try {
					dis.close();
				} catch (Exception e) {

				}
			}
		} catch (Exception e) {

		}

	}
}

对象的输入输出

在java中,不仅仅基本类型的数据可以在流中流动,我们还可以对实例数据进行输入输出。如果某个类的对象需要在流中流动,则该类必须进行序列化与反序列化。所谓对象序列化是把一个对象转换为字节流,反序列化就是把字节流转化为对象。为了实现这个目的,这个类需要实现Serializable接口。

示例1:

/********************************************
*本例将对象数据存入文件中                   *
********************************************/

import java.io.File;
import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.Serializable;

class WriteObjectToFile {
	public static void main(String[] args) {
		File file = new File(args[0]);

		Person p1 = new Person("tom", "01", 20);
		Person p2 = new Person("Jerry", "02", 21);

		try {
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));

			try {
				oos.writeObject(p1);
				oos.writeObject(p2);
			} catch (Exception e) {
				try {
					oos.close();
				} catch (Exception e1) {

				}
			}
		} catch (Exception e) {

		}

	}
}

class Person implements Serializable {

	String name;
	String id;
	/*transient*/ int age;

	public Person(String name, String id, int age) {
		this.name = name;
		this.id = id;
		this.age = age;
	}

	public String toString() {
		return "name = " + name + ", id= " + id + ",age = " + age;
	}
}

示例2:

/********************************************
*本例将对象数据存入文件中                   *
********************************************/

import java.io.File;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.Serializable;

class ReadObjectFromFile {
	public static void main(String[] args) {
		File file = new File(args[0]);

		try {
			ObjectInputStream ios = new ObjectInputStream(new FileInputStream(file));

			try {
				Person person;
				while ((person = (Person)ios.readObject()) != null)
					System.out.println(person);
			} catch (Exception e) {
				try {
					ios.close();
				} catch (Exception e1) {

				}
			}
		} catch (Exception e) {

		}

	}
}

class Person implements Serializable {
	String name;
	String id;
	int age;

	public Person(String name, String id, int age) {
		this.name = name;
		this.id = id;
		this.age = age;
	}

	public String toString() {
		return "name = " + name + ", id= " + id + ",age = " + age;
	}
}

管道的输入输出

管道流是JAVA中线程通讯的常用方式之一,基本流程如下:

  • 创建管道输出流PipedOutputStream pos 和管道输入流PipedInputStream pis
  • pospis匹配,pos.connect(pis);
  • pos传递给输入数据线程,pis传递给获取数据线程,就可以实现线程间的通讯了

管道流只能实现单向发送,如果要两个线程之间互通讯,则需要两个管道流

示例:

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;


public class PipeConnection {

    public static void main(String[] args) throws InterruptedException {
        /**
         * 创建管道输出流
         */
        PipedOutputStream pos = new PipedOutputStream();
        /**
         * 创建管道输入流
         */
        PipedInputStream pis = new PipedInputStream();
        try {
            /**
             * 将管道输入流与输出流连接 此过程也可通过重载的构造函数来实现
             */
            pos.connect(pis);
        } catch (IOException e) {
            e.printStackTrace();
        }
        /**
         * 创建生产者线程
         */
        Producer p = new Producer(pos);
        /**
         * 创建消费者线程
         */
        Consumer c = new Consumer(pis);
        /**
         * 启动线程
         */
        p.start();
        c.start();

        Thread.sleep(5000);

        p.flag = false;
        c.flag = false;
    }
}

/**
 * 生产者线程(与一个管道输入流相关联)
 *
 */
class Producer extends Thread {
    private PipedOutputStream pos;

    boolean flag = true;

    public Producer(PipedOutputStream pos) {
        this.pos = pos;
    }

    public void run() {
        int i = 0;
        try {
            while (flag) {
                this.sleep(1000);
                pos.write(i);
                System.out.println("Producer:" + i);
                i++;
            }
        } catch (Exception e) {
            //e.printStackTrace();
        } 
    }
}

/**
 * 消费者线程(与一个管道输入流相关联)
 *
 */
class Consumer extends Thread {
    private PipedInputStream pis;

    boolean flag = true;

    public Consumer(PipedInputStream pis) {
        this.pis = pis;
    }

    public void run() {
        try {
            while (flag) {
                System.out.println("consumer:" + pis.read());
            }
        } catch (IOException e) {
            //e.printStackTrace();
        } 
    }
}

输入流的逻辑串联

SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达流末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

该类有两个构造方法:

  • public SequenceInputStream(Enumeration<? extends InputStream> e) 通过将需要串联的流通过Enumeration类型的参数,传递给新建的 SequenceInputStream对象。将按顺序读取由该枚举参数生成的输入流,当用尽枚举中的每个输入流之后,将通过调用该流的 close 方法将其关闭。
  • public SequenceInputStream(InputStream s1, InputStream s2) 通过将需要串联的流以两个形式参数来创建新的的 SequenceInputStream对象,将按顺序读取这两个参数,先读取 s1,然后读取 s2。

示例1:

/*
* 本例合并两个文件的内容到一个新的文件中,三个文件的名字由命令行参数指定
* 第一、二为需合并的文件的文件名
* 第三个为合并成的文件名字
*/


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.SequenceInputStream;
import java.io.IOException;
import java.io.FileNotFoundException;

public class CombineFile{
	public static void main(String[] args) throws FileNotFoundException, IOException{
		FileInputStream fis1 = new FileInputStream(args[0]);
		FileInputStream fis2 = new FileInputStream(args[1]);
		FileOutputStream fos = new FileOutputStream(args[2]);

		SequenceInputStream sis = new SequenceInputStream(fis1, fis2);

		int temp;
		while((temp = sis.read())!=-1){
			fos.write(temp);
		}

		sis.close();
		fos.close();
	}
}

PrintStream

PrintStream 类可以把数据以字符的形式打印到流中,比如System.out就是该类类型。该类中提供了printprintlnprintf等方法,与其他输出流不同,PrintStream 永远不会抛出 IOException

PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。

示例:

/********************************************
*本例将几个基本类型的数据以文本存入文件中         *
********************************************/

import java.io.PrintStream;
import java.io.File;

class PrintDataToFile {
	public static void main(String[] args) {
		File file = new File(args[0]);

		try {
			PrintStream ps = new PrintStream(file);

			ps.print(true);
			ps.print(false);
			ps.print(12);
			ps.print(12L);
			ps.print('A');
			ps.print("abc");
			ps.print(1.2f);
			ps.print(1.2);

		} catch (Exception e) {

		}

	}
}

问题

  1. java dir 路径
  2. java dir 路径 文件后缀
  3. java mkdir 路径
  4. java rmdir 路径
  5. java copy 源文件 目的文件

评论 (0)

暂无评论,快来抢沙发吧!