1.文件的概念
- 文件在程序中是以流的形式来操作的
- JAVA程序中目录也被当做文件
- new File只是在JAVA程序内存中创建了File对象,createNewFile才是真实的在硬盘中创建了文件数据
createNewFile
方法内部的实现是依赖于Java平台本身对文件系统的底层操作,并不直接使用Java的流(Stream)API来创建文件。在Java中,流通常用于读取或写入数据,而createNewFile
方法的目标是在文件系统上创建一个新的空文件,而不涉及到数据的读写。当调用
createNewFile
方法时,Java会向操作系统发送一个创建文件的请求。这一过程是通过Java的本地方法接口(JNI)或其他平台特定的机制实现的,以便直接利用操作系统提供的文件系统操作API。这意味着createNewFile
的工作原理和性能特点与操作系统紧密相关,而与Java中的流处理(如FileInputStream
,FileOutputStream
,BufferedReader
,BufferedWriter
等)是分开的。
2.File类及其常用API
Java中的
File
类是java.io
包的一部分,它用于表示文件和目录路径名的抽象表示形式。通过使用File
类,你可以进行文件和目录的创建、文件搜索、删除文件或目录、获取文件属性等操作。File
类不仅可以用于文件处理,还可以用于访问目录中的文件和目录列表。
- 获取文件的相关信息
exists()
: 检查文件或目录是否存在。getName()
: 返回由此File
表示的文件或目录的名称。getAbsolutePath()
: 返回此File
的绝对路径名字符串。isFile()
: 检查由此File
表示的对象是否是一个标准文件。length()
: 返回由此File
表示的文件的长度。list()
: 返回一个字符串数组,这些字符串指定此File
目录中的文件和目录。renameTo(File dest)
: 将此File
重命名为由参数dest
指定的路径名
- 目录的操作和文件删除
isDirectory()
: 检查由此File
表示的对象是否是一个目录。mkdir()
: 创建由此File
表示的目录。delete()
: 删除由此File
表示的文件或目录。
3.项目中用到File类做什么:使用File类一般也离不开使用FileInputStream
- 执行SQL:在项目迁移或者不同的环境下,需要去动态地执行不同的sql脚本,这个时候就需要指定路径读取SQL文件内容,并使用
JdbcTemplate
执行,入参relativePath是指定的相对路径,也就是告诉该方法去哪里找这个sql文件。再用new File把该文件对象创建出来。再将该对象传入new FileInputStream中,如果没有报FileNotFoundException,就证明可以在对应的路径找到该文件。
@Override
public void executeSql(String relativePath, JdbcTemplate jdbcTemplate) {
//标识是否找到要执行的sql文件
boolean exist = false;
String sqlContent = null;
InputStream inputStream = null;
//先尝试在fat jar的home目录查找
//执行方案的目录为 fat jar root path + scheme
String homePath = getHomePath();
String sqlPath = homePath + "/" + relativePath;
File file = new File(sqlPath);
try {
inputStream = new FileInputStream(file);
exist = true;
System.out.println(" 在 " + file + "中找到执行sql");
} catch (FileNotFoundException e) {
exist = false;
}
//如果不存在,尝试在resources下查找
if (!exist) {
try {
Resource resource = new ClassPathResource(relativePath);
inputStream = resource.getInputStream();
System.out.println(" 在 resources/" + relativePath + "中找到执行sql");
exist = true;
} catch (IOException e) {
e.printStackTrace();
exist = false;
}
}
//如果最终找不到抛出异常给上层
if (!exist) {
throw new ServiceException("000", "sql文件【" + relativePath + "】找不到");
}
#找到的SQL文件内容读入sqlContent字符串
sqlContent = FileUtil.readStreamToString(inputStream);
#将sqlContent按";\n"分割成多个SQL语句。这里假设SQL文件中的每条SQL语句都以分号加换行符结束。
String[] sqlArray = sqlContent.split(";\n");
for (String sql : sqlArray) {
//跳过为空的sql
if (StringUtil.isEmpty(sql)) {
continue;
}
jdbcTemplate.execute(sql);
}
}
#这个方法适用于需要根据不同环境或应用版本动态加载和执行SQL脚本的场景,尤其适合于需要数据库迁移和版本控制的复杂应用部署环境。
/**
* 将流转换成一个字符串
*
* @param stream 流
* @return
*/
public static String readStreamToString(InputStream stream) {
StringBuffer fileContentsb = new StringBuffer();
String fileContent = "";
try {
InputStreamReader read = new InputStreamReader(stream, "utf-8");
BufferedReader reader = new BufferedReader(read);
String line;
while ((line = reader.readLine()) != null) {
fileContentsb.append(line + "\n");
}
read.close();
read = null;
reader.close();
read = null;
fileContent = fileContentsb.toString();
} catch (Exception ex) {
fileContent = "";
}
return fileContent;
}
`(line = reader.readLine()) != null`这行代码是在读取文本文件时常用的一种模式,用于逐行读取文件直到文件末尾。这里具体的含义和运作原理如下:
- `reader.readLine()`调用`BufferedReader`的`readLine()`方法来读取文件的下一行。如果文件还有未读取的内容,`readLine()`方法会返回读取到的那一行文本;如果达到文件末尾,`readLine()`方法会返回`null`。
- `line = reader.readLine()`这部分将`readLine()`方法返回的字符串(可能是文件中的一行文本或者`null`)赋值给变量`line`。
- `(line = reader.readLine()) != null`整个表达式的意思是,将`reader.readLine()`的返回值赋值给`line`,然后检查`line`是否不等于`null`。
- 这行代码通常用在`while`循环的条件部分,意味着“只要`readLine()`方法返回的不是`null`(即,只要没有到达文件末尾),就继续执行循环体内的操作”。换句话说,它会逐行读取整个文件,直到没有更多的行可以读取。
这种模式有效地利用了`readLine()`返回`null`这一行为,以此作为循环结束的标志,这样就可以在不知道文件具体行数的情况下,读取文件的所有行。