从文件读取数据并生成对象

这里我们展示数据与代码分离的编程方式。

  • 数据存储在文件中;
  • 程序运行时,通过从文件中读取数据,赋值给程序中要用的对象;
  • 以下例子中,我们用cats.txt存储3只猫猫的数据(name, breed, age):
    • 每一行对应一只猫猫的三个属性,用','分隔;
    • 程序运行时,读取该文件中的每一行,实例化为3只猫猫。

1. 使用Java自带的文件读取功能从文件中读取数据

1.1 准备数据文件目录

  • 右键单击工程名,在工程的根目录创建一个文件夹folderdata。可以将程序需要用到的数据文件放在该文件夹下。
  • 检查工程目录,看data文件夹是否正确创建,并且和src文件夹同级。

Folder Structure

  • 同时其eclipse中的目录结构如下:

Eclipse project structure

1.2 准备数据文件

  • 右键单击data文件夹,在该文件夹下创建数据文件cats.txt
  • 打开cats.txt,填写如下数据:
# name, breed, age
# '#'开头的定义为注释行编程的时候检查如果一行是#开头跳过
# 同时可以有空行编程时检查一行是否为空若为空跳过

Milo, Main coon cat, 5
Leo, Devon Rex, 1
Charlie, Siamese, 3

说明:这里我们自己定义了一个数据的结构:

每一行包含一只猫的三个属性,用','分隔,逗号后可以有空格; 第一个属性是name,第二个属性是breed,第三个属性是age; 如果一行是'#'开头,表明是注释行,解析文件时会直接跳过; 可以有空行。

1.3 创建Cat类

注意检查Class所在的package是否正确.

Cat.java

package javaio;

public class Cat {
	public String name;
	public String breed;
	public int age;
	
	@Override
	public String toString() {
		/*
		 *  重写Cat类的toString方法,
		 *  直接打印一个Cat的对象时,将调用该方法获得需要打印的字符串
		*/
		return String.format("Cat: %s; Breed: %s; Age: %d", name, breed, age);
	}
}

1.4 解析文件,并生成Cat的对象

JavaFileIO.java

package javaio;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class JavaFileIO {

	public static void main(String[] args) {
		/*
		 * 观察该project, 会发现data和src是平级目录 这里用的相对路径,指project下data文件夹下cats.txt文件
		 */
		List<Cat> myCats = getCatsFromFile("data/cats.txt");
		System.out.println("-----------Java File IO Example-----------");
		for (Cat cat : myCats) {
			// 这里调用了Cat的toString方法获取一个字符串直接打印
			System.out.println(cat);
		}

	}

	static List<Cat> getCatsFromFile(String fileName) {
		/*
		 * 用Java自带的File IO 读写文件数据, 从cats.txt中读取数据:每一行对应一只cat的三个属性. 获取所有猫的对象,保存在列表中并返回
		 */

		// 通过fileName创建一个文件(句柄)
		File file = new File(fileName);
		List<Cat> cats = new ArrayList<>();
		try {	// Java的异常处理机制,try{}catch(Exception e){}
			// 创建一个Scanner来逐行扫描文件
			Scanner fileScanner = new Scanner(file);
			// 如果扫描到文件有下一行
			while (fileScanner.hasNext()) {
				String line = fileScanner.nextLine(); // 读取一行
				line = line.trim(); // 删除这一行首尾的空格
				// 如果这一行(去除首位空格后)长度为0,或者以 # 开头,跳过
				if (line.length() == 0 || line.startsWith("#")) {
					continue;
				}
				// 通过','(或后面有空格) 分割字符串,得到一个字符串数组
				String[] catProperties = line.split(",\\s*");
				// 如果分割后,这一行不是包含三个属性(对应于name, breed, age),为不完整数据行,跳过
				if (catProperties.length != 3) {
					continue;
				}
				Cat cat = new Cat();
				cat.name = catProperties[0].trim(); // 第0个属性为name,去除首尾空格
				cat.breed = catProperties[1].trim(); // 第1个属性为breed,去除首尾空格
				// 第三个属性去除首尾空格后,转换成整数,赋值给cat
				cat.age = Integer.parseInt(catProperties[2].trim());
				// 将cat添加进列表
				cats.add(cat);
			}
			// 关闭scanner
			fileScanner.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 返回列表
		return cats;

	}

}

此时,通过读取文件中的数据,创建cats就完成了。
接下来使用Java Stream来实现相同的功能,可以不看。

完整的Project下载,可在Eclipse直接导入

Extended:Java Stream的实现方式

JavaFileStreamIO.java

package javaio;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class JavaFileStreamIO {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Cat> cats = getCatsFromFileStream("data/cats.txt");
		System.out.println("-----------Java File IO with Stream--------  ---");
		for (Cat cat : cats) {
			System.out.println(cat);
		}
	}

	// Java Stream 编程实现
	static List<Cat> getCatsFromFileStream(String fileName) {
		List<Cat> cats = new ArrayList<>();
		try {
			cats = Files.lines(Path.of(fileName))	// 获取每一行组成的stream
					.filter(line -> line.trim().length() > 0 // 筛选非空行
					&& !line.startsWith("#") // 且不以#开头
					&& line.split(",").length == 3) // 且合法(是3个属性)
					.map(line -> { // 将一行转换成一个Cat object
						String[] properties = line.split(",\\s*");
						Cat cat = new Cat();
						cat.name = properties[0];
						cat.breed = properties[1];
						cat.age = Integer.parseInt(properties[2].trim());
						return cat;
					}).collect(Collectors.toList()); // 收集每一行生成的Ojbect,输出一个List
		} catch (Exception e) {
			e.printStackTrace();
		}
		return cats;

	}
}