Training--保存数据(2)-- 保存文件

保存数据(2)-- 保存文件

 

安卓使用的文件系统与其它平台上基于磁盘的文件系统是相似的。本课描述了如何使用File的API接口在安卓的文件系统上读取和写入文件。

 

一个File对象适合以从头至尾连续而非跳跃的顺序读取和写入大量的数据。例如,它比较适合保存通过网络交换的图像文件或其他文件。

 

本课展示了如何在你的应用中执行基本的文件相关的任务。本课程假设你已经熟悉了linux文件系统的基本知识和java.io的输入输出API。

 

选择内部或外部存储

 

所有的安卓设备有两个文件存储区:“内部”和“外部”存储。这些名字来源于早期的安卓历史,那时候大部分设备提供了内置的非易失性的内存(内部存储),外加一个可移除的存储媒介比如一个微型SD卡(外部存储)。一些设备将永久的存储空间也划分为“内部”和“外部”分区,所以即使没有一个可移除的存储媒介,也总是会有两个存储空间,无论外部存储是可移除的或者不可移除,这个API的行为都是一样的。

 

1)       内部存储

 

总是可用的

里面存储的文件默认情况下只能被你的应用访问

当用户卸载你的应用时,系统会把你的应用的所有文件从内部存储上删除

 

2)外部存储

 

并不总是可用,因为用户可以把外部存储安装为USB存储设备,还有一些情况下从设备上卸载掉。

它可以被任何人读取,因此保存在此的文件的读取可能不在你的控制之中。

当用户卸载你的应用时,系统只会删除你保存在getExternalFilesDir()返回的目录下的文件。

 

外部存储特别适合存储那些不需要访问控制的文件,还有你想与其他应用分享的文件或者允许用户通过计算机访问的文件。

 

注意:尽管应用默认安装位置是在内部存储,但是你可以在配置文件中指定android:installLocation值 ,就可以把你的应用安装在外部存储。当APK太大的情况下,用户是比较喜欢这种选择的。

 

获得外部存储的权限

 

为了能在外部存储上写入,你必须在你的配置文件中申请WRITE_EXTERNAL_STORAGE权限:

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

 

警告:目前读取外部存储是不需要特别权限的。但是将来可能有变化。如果你的应用需要读取外部存储,建议你也申请 READ_EXTERANL_STORAGE权限。为了保证将来你的应用能继续工作,你应该在变化发生前,把读取外部存储的权限也写入配置文件:

<manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    ...
</manifest>

 

尽管如此,如果已经申请了WRITE_EXTERNAL_STORAGE权限,那么它隐含地同时申请了READ_EXTERNAL_STORAGE权限。

 

在内部存储上保存文件你不需要申请任何权限。你的应用总是有权限在内部存储目录下读写文件。

 

在内部存储上保存一个文件

 

当向内部存储上保存文件的时候,你可以使用下面两个方法的中的一个返回的File对象作为一个适合的存储目录:

 

getFilesDir()

         为你的应用返回一个代表某个内部存储的目录的File对象。

 

getCacheDir()

         为你的应用的缓存文件提供一个代表某个内部存储目录的File对象。请确定当不需要这些缓存文件的时候,请将它们全部删除,另外也要限制这些缓存文件占用存储空间的大小,比如1MB。如果系统存储空间越来越小的情况下,它有可能直接删除你的缓存文件而不会有任何警告。

 

为了在上面的目录中创建一个新的文件,你可以使用File()构造函数,将上面任一方法返回的File对象作为参数传进去用于指定存储目录。例如:

 

File file = new File(context.getFilesDir(), filename);

 

另外,你也可以调用openFileOutput()得到一个FileOutputStream对象,使用这个对象向内部存储写文件。例如,下面就是如何向一个文件中写入文本的例子:

 

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}

 

否则,如果你需要缓存一些文件,你可以使用createTempFile()接口。例如,下面的方法从一个URL地址提取文件名,然后使用这个名字在你的应用的缓存目录下创建一个文件:

public File getTempFile(Context context, String url) {
    File file;
    try {
        String fileName = Uri.parse(url).getLastPathSegment();
        file = File.createTempFile(fileName, null, context.getCacheDir());
    catch (IOException e) {
        // Error while creating file
    }
    return file;
}

 

注意:你的应用的内部存储目录是使用你的应用的包名存储在安卓文件系统中的某个地方。从技术上讲,如果你设置你的文件模式是可读的,那么其他应用也是可以读取你的内部文件的。但是,其他应用也是需要知道你的应用包名和文件名才行。除非你显式地设置你的文件模式是可读或者可写,否则其他应用是不能浏览你的内部目录,也不能读写你的文件的。只要你把内部存储上的文件设置为MODE_PRIVATE,其他应用是永远无法访问你的文件的。

 

(上面说得也许很抽象,实践出真知啊,关于内部存储,请参考课程“内部文件存储示例”。)

 

在外部存储上保存一个文件

 

因为外部存储不一定可用----比如用户安装外部存储到PC上或者移除的SD卡----你应该在访问它前检查一下外部存储是否可用。你可以调用getExternalStorageState()来获得外部存储的状态。如果返回的状态值是MEDIA_MOUNTED,那么你可以读写文件了。例如,下面的方法对于检查存储的可用性非常有用:

 

/* 检查外部存储是否可读写 */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* 检查外部存储是否是只读 */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

 

尽管用户和其他应用可以修改外部存储,但是你保存的文件类型还是应该属于下面两种中的一种:

 

公有文件

这种文件应该对其他应用和用户都是可用的。当用户卸载你的应用时,这些文件对用户还是保持可用的。

 

         例如, 你的应用捕获的图像或者下载的文件。

 

私有文件

这种文件只属于你的应用,当用户卸载你的应用时,这种文件也会被删除。尽管从技术上讲,这种文件仍然可以被其他应用和用户访问,因为它们毕竟是存储在外部存储上的,但是实际上这些文件对于其他应用和用户并不能提供什么价值。当用户卸载你的应用时,系统会删除你的应用的外部私有目录下的所有文件。

         例如,你的应用下载的额外资源或者临时媒体文件。

 

如果你想在外部存储上保存公有文件,你可以调用方法getExternalStoragePublicDirectory()获得一个File对象,这个对象代表了外部存储上一个公共目录。这个方法接受一个关于文件类型的参数,能够和其他公共文件进行逻辑上的划分,如参数DIRECTORY_MUSIC 或 DIRECTORY_PICUTURES。例如:

 

public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory. 
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

 

如果你想保存一些对于你的应用是私有的文件,那么你可以调用getExternalFilesDir()获得一个合理的目录,然后传进去一个文件类型参数。所有以这种形式创建的目录都被放到你的应用对应的外部存储的根目录,当用户卸载你的应用时,这些根目录下的文件都会被删除。

 

例如,你可以使用下面的方法创建一个私有的相册目录:

 

public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory. 
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

 

如果任何预定义的文件类型目录都不适合你要创建的文件的话,你可以调用getExternalFilesDir(),将参数设为null。此时返回一个指向你的外部存储的私有文件的根目录。

 

记住getExternalFilesDir()创建的目录,当用户卸载你的应用时,都会被删除的。如果你想让你的文件在你的应用被卸载后依然可用的话---例如,你的应用是一个相机,用户希望保存下来图片—你应该使用getExternalStoragePublicDirectory()。

 

无论你是使用getExternalStoragePublicDirectory()创建公有的文件还是使用getExternalFilesDir()创建私有的文件,你最好使用API常量提供的目录名字例如DIRECTORY_PICTURES。这种类型的目录名字能够保证被系统合理地对待。比如,系统媒体扫描器会将DIRECTOREY_RINGTONE下的文件认为是铃声文件而不会作为音乐文件。

 

 

 

检查可用空间

 

如果事先你能知道要保存多少数据,你可以调用getFreeSpace()或getTotalSpace()来检查还有多少剩余空间,这样保存文件的时候就不会由于可用空间不足而引起IOException。

 

尽管如此,系统并不能保证你可以写入getFreeSpace()大小的空间。如果剩余的空间比你要写的数据大几MB的话,或者文件系统占用的空间不足90%的话,那么可能继续写文件系统是安全的。否则,你不应该再写文件了。

 

删除一个文件

 

你应该删除那些不再需要的文件。最直接简单的办法就是直接在File对象上使用delete()方法:

 

myFile.delete();

 

如果文件存储在内部存储上,你可以使用Context定位文件然后调用delteFile():

 

myContext.deleteFile(fileName);

 

注意:当用户卸载你的应用的时候,系统会删除以下文件:

所有内部存储上的文件

所有保存在外部存储上getExternalFilesDir()目录下的文件

 

尽管如此,你可以手动删除使用getCacheDir()创建的缓存文件还有其他不再需要的文件。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个用于CS-Net训练的Python脚本模板,包含了一些基本的训练步骤和参数设置: ```python import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from dataset import CustomDataset from model import CSNet # 设置训练参数 epochs = 100 batch_size = 32 learning_rate = 0.001 # 构建模型和优化器 model = CSNet() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # 加载训练数据 train_dataset = CustomDataset(train=True) train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 加载验证数据 val_dataset = CustomDataset(train=False) val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False) # 定义损失函数 criterion = nn.MSELoss() # 开始训练 for epoch in range(epochs): model.train() # 将模型设置为训练模式 train_loss = 0.0 for i, data in enumerate(train_loader): # 将数据传入模型进行训练 inputs, labels = data optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() # 计算训练损失 train_loss += loss.item() * inputs.size(0) # 在验证集上计算损失 model.eval() # 将模型设置为评估模式 val_loss = 0.0 with torch.no_grad(): for i, data in enumerate(val_loader): inputs, labels = data outputs = model(inputs) loss = criterion(outputs, labels) val_loss += loss.item() * inputs.size(0) # 输出训练和验证损失 train_loss /= len(train_dataset) val_loss /= len(val_dataset) print("Epoch: {}, Train Loss: {:.6f}, Val Loss: {:.6f}".format(epoch+1, train_loss, val_loss)) # 保存模型 torch.save(model.state_dict(), "csnet.pth") ``` 在这个脚本中,我们首先设置了训练参数(例如训练轮数、批次大小、学习率等),然后构建了CS-Net模型和Adam优化器。接着,我们加载了训练和验证数据集,并定义了损失函数。在训练过程中,我们使用`DataLoader`迭代训练数据,将数据传入模型进行训练,并计算训练损失。在每个epoch结束后,我们使用验证数据集计算验证损失,并输出训练和验证损失。最后,我们保存了训练好的模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值