File file1_str = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera1/1.ini"); 如何向1.ini写入内容和读取内容
时间: 2025-07-29 11:35:54 浏览: 5
<think>我们使用标准的JavaI/O流操作来写入和读取文件内容。由于文件位于外部存储,需要确保已经获取了外部存储的写入权限(在AndroidManifest.xml中声明WRITE_EXTERNAL_STORAGE权限,并且在Android6.0及以上版本动态请求权限)。步骤:1.检查外部存储是否可用(可写)。2.使用FileOutputStream写入内容。3.使用FileInputStream读取内容。注意:在Android10及以上版本,由于分区存储(ScopedStorage)的限制,访问外部存储的方式有所变化。如果目标API级别>=29,可能需要使用MediaStore或者其他方法。但这里我们假设应用有权限访问该路径(例如,通过requestLegacyExternalStorage或者应用的目标SDK版本低于29)。以下是写入和读取文件的代码示例:</think>### 在 Android 中读写外部存储中的 INI 文件
以下是完整的解决方案,用于在 Android 设备的外部存储(如 `/sdcard/DCIM/Camera1/1.ini`)中读写 INI 文件内容。INI 文件是一种简单的配置文件格式,通常包含键值对。
#### 1. 权限配置
首先在 `AndroidManifest.xml` 中添加必要的权限:
```xml
<!-- 外部存储读写权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 10+ 需要额外声明 -->
<application
android:requestLegacyExternalStorage="true"
...>
</application>
```
#### 2. 动态权限请求(Android 6.0+)
```java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_STORAGE_PERMISSION = 1;
private static final String FILE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera1/1.ini";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 检查并请求权限
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(
new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
},
REQUEST_STORAGE_PERMISSION
);
} else {
initFileOperations();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_STORAGE_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initFileOperations();
} else {
Toast.makeText(this, "需要存储权限才能操作文件", Toast.LENGTH_SHORT).show();
}
}
}
private void initFileOperations() {
// 初始化文件操作
File iniFile = new File(FILE_PATH);
// 写入示例
Button writeBtn = findViewById(R.id.writeBtn);
writeBtn.setOnClickListener(v -> {
Map<String, String> data = new HashMap<>();
data.put("resolution", "1920x1080");
data.put("quality", "high");
data.put("last_modified", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date()));
writeIniFile(iniFile, data);
});
// 读取示例
Button readBtn = findViewById(R.id.readBtn);
readBtn.setOnClickListener(v -> {
Map<String, String> content = readIniFile(iniFile);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : content.entrySet()) {
sb.append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n");
}
TextView resultView = findViewById(R.id.resultView);
resultView.setText(sb.toString());
});
}
}
```
#### 3. INI 文件读写工具类
```java
public class IniFileUtils {
// 写入 INI 文件
public static boolean writeIniFile(File file, Map<String, String> data) {
// 确保目录存在
File parentDir = file.getParentFile();
if (!parentDir.exists() && !parentDir.mkdirs()) {
Log.e("IniFileUtils", "无法创建目录: " + parentDir.getAbsolutePath());
return false;
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
for (Map.Entry<String, String> entry : data.entrySet()) {
// 写入键值对:key=value
writer.write(entry.getKey() + "=" + entry.getValue());
writer.newLine();
}
writer.flush();
return true;
} catch (IOException e) {
Log.e("IniFileUtils", "写入文件失败: " + file.getAbsolutePath(), e);
return false;
}
}
// 读取 INI 文件
public static Map<String, String> readIniFile(File file) {
Map<String, String> result = new HashMap<>();
if (!file.exists()) {
Log.w("IniFileUtils", "文件不存在: " + file.getAbsolutePath());
return result;
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
// 跳过空行和注释
if (line.trim().isEmpty() || line.trim().startsWith("#") || line.trim().startsWith(";")) {
continue;
}
// 解析键值对
int separatorIndex = line.indexOf('=');
if (separatorIndex > 0) {
String key = line.substring(0, separatorIndex).trim();
String value = line.substring(separatorIndex + 1).trim();
result.put(key, value);
}
}
} catch (IOException e) {
Log.e("IniFileUtils", "读取文件失败: " + file.getAbsolutePath(), e);
}
return result;
}
// 更新特定键的值
public static boolean updateIniValue(File file, String key, String newValue) {
Map<String, String> currentData = readIniFile(file);
currentData.put(key, newValue);
return writeIniFile(file, currentData);
}
// 删除特定键
public static boolean removeIniKey(File file, String key) {
Map<String, String> currentData = readIniFile(file);
if (currentData.containsKey(key)) {
currentData.remove(key);
return writeIniFile(file, currentData);
}
return false;
}
}
```
#### 4. 处理 Android 10+ 的分区存储 (Scoped Storage)
对于 Android 10 (API 29) 及以上版本,需要使用 MediaStore 或 SAF 访问文件:
```java
// 使用 MediaStore 写入文件 (Android 10+)
public static boolean writeIniFileWithMediaStore(Context context, String fileName, Map<String, String> data) {
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
values.put(MediaStore.MediaColumns.MIME_TYPE, "text/plain");
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/Camera1");
try {
Uri uri = resolver.insert(MediaStore.Files.getContentUri("external"), values);
if (uri == null) return false;
try (OutputStream os = resolver.openOutputStream(uri);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os))) {
for (Map.Entry<String, String> entry : data.entrySet()) {
writer.write(entry.getKey() + "=" + entry.getValue());
writer.newLine();
}
writer.flush();
return true;
}
} catch (IOException e) {
Log.e("IniFileUtils", "MediaStore写入失败", e);
return false;
}
}
// 使用 MediaStore 读取文件 (Android 10+)
public static Map<String, String> readIniFileWithMediaStore(Context context, String fileName) {
Map<String, String> result = new HashMap<>();
ContentResolver resolver = context.getContentResolver();
Uri collection = MediaStore.Files.getContentUri("external");
String[] projection = { MediaStore.Files.FileColumns._ID };
String selection = MediaStore.Files.FileColumns.RELATIVE_PATH + "=? AND " +
MediaStore.Files.FileColumns.DISPLAY_NAME + "=?";
String[] selectionArgs = new String[] {
Environment.DIRECTORY_DCIM + "/Camera1",
fileName
};
try (Cursor cursor = resolver.query(collection, projection, selection, selectionArgs, null)) {
if (cursor != null && cursor.moveToFirst()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID));
Uri fileUri = ContentUris.withAppendedId(collection, id);
try (InputStream is = resolver.openInputStream(fileUri);
BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.trim().isEmpty() || line.trim().startsWith("#")) continue;
int separatorIndex = line.indexOf('=');
if (separatorIndex > 0) {
String key = line.substring(0, separatorIndex).trim();
String value = line.substring(separatorIndex + 1).trim();
result.put(key, value);
}
}
}
}
} catch (IOException e) {
Log.e("IniFileUtils", "MediaStore读取失败", e);
}
return result;
}
```
#### 5. 高级 INI 文件处理(支持节)
对于更复杂的 INI 文件(包含节):
```java
// 支持节的 INI 文件结构
public static Map<String, Map<String, String>> readIniFileWithSections(File file) {
Map<String, Map<String, String>> result = new LinkedHashMap<>();
Map<String, String> currentSection = null;
if (!file.exists()) return result;
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
// 跳过空行和注释
if (line.isEmpty() || line.startsWith("#") || line.startsWith(";")) {
continue;
}
// 解析节 [section]
if (line.startsWith("[") && line.endsWith("]")) {
String sectionName = line.substring(1, line.length() - 1).trim();
currentSection = new LinkedHashMap<>();
result.put(sectionName, currentSection);
continue;
}
// 解析键值对
if (currentSection != null) {
int separatorIndex = line.indexOf('=');
if (separatorIndex > 0) {
String key = line.substring(0, separatorIndex).trim();
String value = line.substring(separatorIndex + 1).trim();
currentSection.put(key, value);
}
}
}
} catch (IOException e) {
Log.e("IniFileUtils", "读取带节的文件失败", e);
}
return result;
}
// 写入带节的 INI 文件
public static boolean writeIniFileWithSections(File file, Map<String, Map<String, String>> data) {
File parentDir = file.getParentFile();
if (!parentDir.exists() && !parentDir.mkdirs()) {
return false;
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
for (Map.Entry<String, Map<String, String>> section : data.entrySet()) {
// 写入节头
writer.write("[" + section.getKey() + "]");
writer.newLine();
// 写入键值对
for (Map.Entry<String, String> entry : section.getValue().entrySet()) {
writer.write(entry.getKey() + " = " + entry.getValue());
writer.newLine();
}
// 节之间空行
writer.newLine();
}
return true;
} catch (IOException e) {
Log.e("IniFileUtils", "写入带节的文件失败", e);
return false;
}
}
```
#### 6. 文件监控和自动重载
```java
public class IniFileWatcher {
private final File file;
private final OnFileChangedListener listener;
private FileObserver fileObserver;
private long lastModified = 0;
public interface OnFileChangedListener {
void onFileChanged(Map<String, String> newContent);
}
public IniFileWatcher(File file, OnFileChangedListener listener) {
this.file = file;
this.listener = listener;
startWatching();
}
private void startWatching() {
if (fileObserver != null) return;
fileObserver = new FileObserver(file.getParentFile().getAbsolutePath()) {
@Override
public void onEvent(int event, String path) {
if (path != null && path.equals(file.getName())) {
if ((event & FileObserver.MODIFY) != 0) {
long currentModified = file.lastModified();
if (currentModified > lastModified) {
lastModified = currentModified;
reloadFile();
}
}
}
}
};
fileObserver.startWatching();
reloadFile(); // 初始加载
}
private void reloadFile() {
new Thread(() -> {
Map<String, String> content = IniFileUtils.readIniFile(file);
new Handler(Looper.getMainLooper()).post(() -> {
listener.onFileChanged(content);
});
}).start();
}
public void stopWatching() {
if (fileObserver != null) {
fileObserver.stopWatching();
fileObserver = null;
}
}
}
// 使用示例
public class MainActivity extends AppCompatActivity {
private IniFileWatcher fileWatcher;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... 其他代码 ...
File iniFile = new File(FILE_PATH);
fileWatcher = new IniFileWatcher(iniFile, newContent -> {
// 当文件变化时更新UI
TextView resultView = findViewById(R.id.resultView);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : newContent.entrySet()) {
sb.append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n");
}
resultView.setText(sb.toString());
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (fileWatcher != null) {
fileWatcher.stopWatching();
}
}
}
```
### 关键注意事项
1. **权限处理**:
- Android 6.0+ 需要动态请求权限
- Android 10+ 需要处理分区存储
- Android 11+ 需要 MANAGE_EXTERNAL_STORAGE 权限
2. **文件路径**:
- 使用 `Environment.getExternalStorageDirectory()` 获取外部存储根目录
- 考虑不同设备的路径差异
- 使用 `Context.getExternalFilesDir()` 获取应用专属外部存储
3. **错误处理**:
- 检查文件是否存在
- 处理 IO 异常
- 处理空文件或无效格式
4. **性能优化**:
- 大文件使用缓冲读写
- 避免主线程文件操作
- 使用缓存减少重复读取
5. **线程安全**:
```java
private static final Object fileLock = new Object();
public static boolean writeIniFile(File file, Map<String, String> data) {
synchronized (fileLock) {
// 文件操作代码
}
}
```
### 完整示例:INI 配置管理器
```java
public class IniConfigManager {
private final File configFile;
private Map<String, String> cachedConfig;
private long lastLoadTime;
public IniConfigManager(String filePath) {
this.configFile = new File(filePath);
loadConfig();
}
public String getValue(String key, String defaultValue) {
synchronized (this) {
if (cachedConfig == null || configFile.lastModified() > lastLoadTime) {
loadConfig();
}
return cachedConfig.getOrDefault(key, defaultValue);
}
}
public boolean setValue(String key, String value) {
synchronized (this) {
if (cachedConfig == null) loadConfig();
cachedConfig.put(key, value);
return writeConfig();
}
}
public boolean removeKey(String key) {
synchronized (this) {
if (cachedConfig == null) loadConfig();
if (cachedConfig.remove(key) != null) {
return writeConfig();
}
return false;
}
}
private void loadConfig() {
cachedConfig = IniFileUtils.readIniFile(configFile);
lastLoadTime = System.currentTimeMillis();
}
private boolean writeConfig() {
boolean success = IniFileUtils.writeIniFile(configFile, cachedConfig);
if (success) {
lastLoadTime = configFile.lastModified();
}
return success;
}
}
```
###
阅读全文
相关推荐


















