# 文件存储

## 目录
- [内部存储](#内部存储)
- [外部存储](#外部存储)
- [文件操作](#文件操作)
- [文件权限](#文件权限)
- [文件加密](#文件加密)
- [文件存储最佳实践](#文件存储最佳实践)
- [面试常见问题](#面试常见问题)

---

## 内部存储

### 内部存储特点

```java
// 内部存储：
// - 应用私有，其他应用无法访问
// - 卸载应用时自动删除
// - 不需要权限
// - 路径：/data/data/<package_name>/files/
```

### 内部存储使用

```java
// 写入文件
String filename = "myfile.txt";
String content = "Hello World";

try (FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE)) {
    fos.write(content.getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

// 读取文件
try (FileInputStream fis = openFileInput(filename)) {
    byte[] buffer = new byte[1024];
    int length = fis.read(buffer);
    String content = new String(buffer, 0, length);
} catch (IOException e) {
    e.printStackTrace();
}

// 删除文件
deleteFile(filename);

// 列出文件
String[] files = fileList();
```

### 存储模式

```java
// MODE_PRIVATE：私有模式（默认）
openFileOutput(filename, Context.MODE_PRIVATE);

// MODE_APPEND：追加模式
openFileOutput(filename, Context.MODE_APPEND);

// MODE_WORLD_READABLE：可读（已废弃）
// MODE_WORLD_WRITEABLE：可写（已废弃）
```

---

## 外部存储

### 外部存储特点

```java
// 外部存储：
// - 可以被其他应用访问（需要权限）
// - 卸载应用时不会自动删除
// - 需要权限（Android 6.0+）
// - 路径：/sdcard/ 或 /storage/emulated/0/
```

### 外部存储使用

#### Android 10 之前

```java
// 检查外部存储是否可用
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    // 外部存储可用
    
    // 获取外部存储目录
    File externalDir = Environment.getExternalStorageDirectory();
    File file = new File(externalDir, "myfile.txt");
    
    // 写入文件
    try (FileWriter writer = new FileWriter(file)) {
        writer.write("Hello World");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
```

#### Android 10+（分区存储）

```java
// 使用 MediaStore 访问文件
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, "image.jpg");
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
    
    Uri uri = getContentResolver().insert(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    
    try (OutputStream os = getContentResolver().openOutputStream(uri)) {
        // 写入文件
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
```

### 应用私有外部存储

```java
// 应用私有外部存储
// 路径：/sdcard/Android/data/<package_name>/
// 卸载应用时自动删除

File externalFilesDir = getExternalFilesDir(null);
File file = new File(externalFilesDir, "myfile.txt");
```

---

## 文件操作

### 文件读写

```java
// 写入文件
public void writeFile(String filename, String content) {
    try (FileWriter writer = new FileWriter(filename)) {
        writer.write(content);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// 读取文件
public String readFile(String filename) {
    StringBuilder content = new StringBuilder();
    try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
        String line;
        while ((line = reader.readLine()) != null) {
            content.append(line).append("\n");
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return content.toString();
}
```

### 文件复制

```java
public void copyFile(File source, File dest) {
    try (InputStream is = new FileInputStream(source);
         OutputStream os = new FileOutputStream(dest)) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = is.read(buffer)) > 0) {
            os.write(buffer, 0, length);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
```

### 文件删除

```java
// 删除文件
File file = new File(path);
if (file.exists()) {
    file.delete();
}

// 删除目录
public void deleteDirectory(File directory) {
    if (directory.exists()) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    file.delete();
                }
            }
        }
        directory.delete();
    }
}
```

---

## 文件权限

### 权限申请

```java
// Android 6.0+ 需要运行时申请
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(
            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
            REQUEST_CODE);
    }
}
```

### Android 10+ 权限变化

```java
// Android 10+ 分区存储
// - 应用私有目录：不需要权限
// - 共享存储：使用 MediaStore，不需要权限
// - 其他目录：需要 MANAGE_EXTERNAL_STORAGE 权限
```

---

## 文件加密

### 文件加密示例

```java
// 使用 AES 加密
public void encryptFile(File inputFile, File outputFile, String password) {
    try {
        SecretKeySpec key = new SecretKeySpec(
            password.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        
        try (FileInputStream fis = new FileInputStream(inputFile);
             FileOutputStream fos = new FileOutputStream(outputFile);
             CipherOutputStream cos = new CipherOutputStream(fos, cipher)) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                cos.write(buffer, 0, length);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
```

---

## 文件存储最佳实践

### 1. 选择合适的存储位置

```java
// 应用私有数据 → 内部存储
// 用户生成内容 → 外部存储（应用私有目录）
// 共享文件 → MediaStore
```

### 2. 及时关闭流

```java
// ✅ 使用 try-with-resources
try (FileInputStream fis = new FileInputStream(file)) {
    // 使用流
}

// ❌ 忘记关闭流
FileInputStream fis = new FileInputStream(file);
// 使用流
// 忘记关闭，可能导致资源泄漏
```

### 3. 异步操作

```java
// 文件操作在后台线程执行
new Thread(() -> {
    writeFile(file, content);
    runOnUiThread(() -> {
        // 更新 UI
    });
}).start();
```

---

## 面试常见问题

### Q1: 内部存储和外部存储的区别？

**答案：**
- **内部存储**：应用私有，卸载时删除，不需要权限
- **外部存储**：可被其他应用访问，卸载时不删除，需要权限

### Q2: Android 10 分区存储？

**答案：**
- 限制应用访问外部存储
- 使用 MediaStore 访问媒体文件
- 使用 SAF 访问其他文件
- 提升用户隐私保护

### Q3: 文件存储的权限？

**答案：**
- **内部存储**：不需要权限
- **外部存储**：Android 6.0+ 需要运行时申请
- **Android 10+**：应用私有目录不需要权限

---

*最后更新：2024年*
