Java文件处理全解析
立即解锁
发布时间: 2025-08-20 00:52:11 订阅数: 12 

### Java文件处理全解析
#### 1. Java文件的逻辑结构
在Java中,文件本身并没有预设的结构,程序员需要自行对文件施加所需的逻辑结构。文件中的“记录”并非由Java或操作系统决定的物理单元,而是由程序员建立和维护的逻辑单元。
例如,若要创建一个存储客户账户详细信息的文件,每个逻辑记录可能包含以下字段:
- 账户号码
- 客户姓名
- 账户余额
程序员有责任确保文件中的每个逻辑记录恰好包含这三个字段,并且它们按照指定的顺序出现。
#### 2. Java文件类的重要方法
Java的`File`类提供了大量方法,以下是其中一些重要的方法:
| 方法 | 描述 |
| --- | --- |
| `boolean canRead()` | 如果文件可读则返回`true`,否则返回`false` |
| `boolean canWrite()` | 如果文件可写则返回`true`,否则返回`false` |
| `boolean delete()` | 删除文件,成功返回`true`,失败返回`false` |
| `boolean exists()` | 如果文件存在则返回`true`,否则返回`false` |
| `String getName()` | 返回文件的名称 |
| `boolean isDirectory()` | 如果对象是目录则返回`true`,否则返回`false` |
| `boolean isFile()` | 如果对象是文件则返回`true`,否则返回`false` |
| `long length()` | 返回文件的字节长度 |
| `String[] list()` | 如果对象是目录,返回该目录下的文件名称数组 |
| `File[] listFiles()` | 与`list()`类似,但返回`File`对象数组 |
| `boolean mkdir()` | 创建以当前`File`对象命名的目录,返回值表示创建是否成功 |
以下是一个示例代码,展示了如何使用这些方法:
```java
import java.io.*;
import java.util.*;
public class FileMethods
{
public static void main(String[] args)
throws IOException
{
String filename;
Scanner input = new Scanner(System.in);
System.out.print(
"Enter name of file/directory ");
System.out.print("or press <Enter> to quit: ");
filename = input.nextLine();
while (!filename.equals("")) //Not <Enter> key.
{
File fileDir = new File(filename);
if (!fileDir.exists())
{
System.out.println(filename
+ " does not exist!");
break; //Get out of loop.
}
System.out.print(filename + " is a ");
if (fileDir.isFile())
System.out.println("file.");
else
System.out.println("directory.");
System.out.print("It is ");
if (!fileDir.canRead())
System.out.print("not ");
System.out.println("readable.");
System.out.print("It is ");
if (!fileDir.canWrite())
System.out.print("not ");
System.out.println("writeable.");
if (fileDir.isDirectory())
{
System.out.println("Contents:");
String[] fileList = fileDir.list();
//Now display list of files in
//directory…
for (int i=0;i<fileList.length;i++)
System.out.println(" "
+ fileList[i]);
}
else
{
System.out.print("Size of file: ");
System.out.println(fileDir.length()
+ " bytes.");
}
System.out.print(
"\n\nEnter name of next file/directory ");
System.out.print(
"or press <Enter> to quit: ");
filename = input.nextLine();
}
input.close();
}
}
```
这个程序允许用户输入文件或目录的名称,然后显示该文件或目录的相关属性。
#### 3. 输入输出重定向
默认情况下,标准输入流`System.in`与键盘关联,标准输出流`System.out`与VDU(视频显示单元)关联。但如果我们希望输入来自其他源(如文本文件),或者输出到除VDU屏幕之外的地方,就可以进行输入输出重定向。
重定向在调试需要用户输入多个数据项的程序时非常有用。我们可以使用`<`指定新的输入源,使用`>`指定新的输出目标。
示例:
```
java ReadData < payroll.txt
java WriteData > results.txt
```
当执行第一行代码时,程序`ReadData(.class)`正常执行,但每当遇到文件输入语句(通过`Scanner`方法`next`、`nextLine`、`nextInt`等)时,它将从文件`payroll.txt`中获取下一个可用的数据项。同样,程序`WriteData(.class)`将把所有`print`和`println`语句的输出定向到文件`results.txt`。
我们也可以对同一个程序同时进行输入和输出重定向,例如:
```
java ProcessData < readings.txt > results.txt
```
对于程序`ProcessData(.class)`,所有文件输入语句将从文件`readings.txt`中读取数据,而所有`print`和`println`语句将把输出发送到文件`results.txt`。
#### 4. 命令行参数
在命令窗口中输入`java`命令时,除了要执行的程序名称外,还可以提供其他值。这些值称为命令行参数,程序可以使用这些值。这些值通过`main`方法以`String`数组的形式接收。
例如,假设一个编译后的Java程序`Copy.class`用于将一个文件的内容复制到另一个文件。我们可以通过命令行参数指定这两个文件的名称:
```
java Copy source.dat dest.dat
```
以下是该程序的代码:
```java
import java.io.*;
import java.util.*;
public class Copy
{
public static void main(String[] arg)
throws IOException
{
//First check that 2 file names have been
//supplied…
if (arg.length < 2)
{
System.out.println(
"You must supply TWO file names.");
System.out.println("Syntax:");
System.out.println(
" java Copy <source> <destination>");
return;
}
Scanner source = new Scanner(new File(arg[0]));
PrintWriter destination =
new PrintWriter(new File(arg[1]));
String input;
while (source.hasNext())
{
input = source.nextLine();
destination.println(input);
}
source.close();
destination.close();
}
}
```
#### 5. 随机访问文件
串行访问文件处理简单,在小规模应用或大规模应用的临时存储中广泛使用。但它有两个明显的缺点:
- 无法直接访问特定记录,要访问某个特定记录,必须物理地读取前面的所有记录,对于包含数千条记录的应用来说,这是不可行的。
- 无法在现有文件中添加或修改记录,必须重新创建整个文件。
随机访问文件(更准确地称为直接访问文件)克服了这些问题,但也有自身的缺点:
- 通常,特定文件中的所有(逻辑)记录必须具有相同的长度。
- 同样,文件中所有记录的给定字符串字段必须具有相同的长度。
- 数值数据不是人类可读的形式。
然而,随机访问文件的速度和灵活性通常远远超过上述缺点。在许多实际应用中,直接访问是唯一可行的选择。
在Java中,我们可以通过创建`RandomAccessFile`对象来创建随机访问文件。构造函数需要两个参数:
- 一个字符串或`File`对象,用于标识文件。
- 一个字符串,用于指定文件的访问模式,可以是“r”(只读访问)或“rw”(读写访问)。
例如:
```java
RandomAccessFile ranFile = new RandomAccessFile("accounts.dat","rw");
```
在读取或写入记录之前,需要定位文件指针。我们可以通过调用`seek`方法来实现,该方法需要一个参数,指定文件中的字节位置(文件的第一个字节是字节0)。
例如:
```java
ranFile.seek(500); //Move to byte 500 (the 501st byte).
```
为了移动到特定记录的正确位置,我们需要知道两件事:
- 文件中记录的大小。
- 计算适当位置的算法。
以下是一个示例,展示如何设置一个包含特定字段的账户文件:
假设我们要设置一个包含以下字段的账户文件:
- 账户号码(`long`类型)
- 姓氏(`String`类型)
- 名字首字母(`String`类型)
- 账户余额(`float`类型)
我们决定为姓氏分配15个(Unicode)字符,为名字首字母分配3个(Unicode)字符。由于每个Unicode字符占用2个字节,每个姓氏将分配30字节(即15×2),每个名字首字母集将分配6字节(即3×2)。又因为`long`类型占用8字节,`float`类型占用4字节,所以每个记录的大小为(8 + 30 + 6 + 4)字节 = 48字节。
记录将从字节位置0、48、96等开始存储。计算文件中任何记录位置的公式为:
```
(Record No. – 1) × 48
```
例如,假设我们的`RandomAccessFile`对象名为`ranAccts`,要定位账户号码为5的记录,可以使用以下代码:
```java
ranAccts.seek(192); //(5–1)x48 = 192
```
由于`length`方法返回文件的字节数,我们可以通过将文件大小除以单个记录的大小来计算随机访问文件中的记录数。因此,文件`ranAccts`在任何给定时间的记录数为`ranAccts.length()/48`。
以下是完整的示例代码:
```java
import java.io.*;
import java.util.*;
public class RanFile1
{
private static final int REC_SIZE = 48;
private static final int SURNAME_SIZE = 15;
private static final int NUM_INITS = 3;
private static long acctNum = 0;
private static String surname, initials;
private static float balance;
public static void main(String[] args)
throws IOException
{
RandomAccessFile ranAccts =
new RandomAccessFile("accounts.dat", "rw");
Scanner input = new Scanner(System.in);
String reply = "y";
do
{
acctNum++;
System.out.println(
"\nAccount number " + acctNum + ".\n");
System.out.print("Surname: ");
surname = input.nextLine();
System.out.print("Initial(s): ");
init
```
0
0
复制全文
相关推荐









