将文件保存在设备存储上
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将文件保存在设备存储上相关的知识,希望对你有一定的参考价值。
参考技术A File对象适用于从头到尾读取或写入大量数据而不会跳过。 例如,它适用于图像文件或通过网络交换的任何内容。保存文件的位置的确切位置可能因设备而异,因此您应该使用此页面中描述的方法来访问内部和外部存储路径,而不是使用绝对文件路径。
要查看设备上的文件,您可以记录 File.getAbsolutePath() 等方法提供的文件位置,然后使用android Studio的 Device File Explorer 浏览设备文件。
所有Android设备都有两个文件存储区:“内部”和“外部”存储。 这些名称来自Android的早期,当时大多数设备提供内置的非易失性存储器(内部存储),以及可移动存储介质,如micro SD卡(外部存储)。 现在,许多设备将永久存储空间划分为单独的“内部”和“外部”分区。 因此,即使没有可移动存储介质,这两个存储空间也始终存在,无论外部存储是否可移动,API行为都是相同的。
由于外部存储可能是可移除的,因此这两个选项之间存在一些差异,如下所示。
如果您想确保用户和其他应用程序都无法访问您的文件,则最好使用内部存储。
对于不需要访问限制的文件以及要与其他应用程序共享或允许用户使用计算机访问的文件,外部存储是最佳位置。
您的应用程序的内部存储目录由您的应用程序包名称指定在Android文件系统的特定位置,可以使用以下API访问。
将文件保存到内部存储时,可以通过调用以下两种方法之一获取相应的目录作为文件:
返回表示应用程序内部目录的文件。
返回表示应用程序临时缓存文件的内部目录的文件。 确保在不再需要时删除每个文件,并对在任何给定时间使用的内存量(例如1MB)实施合理的大小限制。
要在其中一个目录中创建新文件,可以使用 File() 构造函数,传递上述方法之一提供的文件,该方法指定您的内部存储目录。 例如:
或者,您可以调用 openFileOutput() 来获取写入内部目录中文件的FileOutputStream。 例如,以下是如何将一些文本写入文件:
请注意, openFileOutput() 方法需要文件模式参数。 传递 MODE_PRIVATE 会使其对您的应用程序保密。 自API级别17以来,其他模式选项 MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 已被弃用。从Android 7.0(API级别24)开始,如果您使用Android,则会抛出 SecurityException 。 如果您的应用需要与其他应用共享私有文件,则应使用带有 FLAG_GRANT_READ_URI_PERMISSION 的 FileProvider 。
在Android 6.0(API级别23)及更低级别上,如果您将文件模式设置为全局可读,则其他应用程序可以读取您的内部文件。 但是,其他应用必须知道您的应用包名称和文件名。 除非您明确将文件设置为可读或可写,否则其他应用程序无法浏览您的内部目录并且没有读取或写入权限。 因此,只要您将MODE_PRIVATE用于内部存储上的文件,其他应用就永远无法访问它们。
如果您需要缓存某些文件,则应使用 createTempFile() 。 例如,以下方法从URL中提取文件名,并在应用程序的内部缓存目录中创建具有该名称的文件:
使用 createTempFile() 创建的文件放在应用程序专用的缓存目录中。 您应该定期删除不再需要的文件。
要读取现有文件,请调用 openFileInput(name) ,传递文件名。
您可以通过调用 fileList() 获取所有应用程序文件名的数组。
您可以使用以下方法在内部文件系统上打开目录:
返回表示文件系统上与您的应用唯一关联的目录的文件。
在应用程序的唯一文件系统目录中创建新目录(或打开现有目录)。 这个新目录出现在 getFilesDir() 提供的目录中。
返回一个文件,表示文件系统上与您的应用唯一关联的缓存目录。 此目录适用于临时文件,应定期清理。 如果磁盘空间不足,系统可能会删除那里的文件,因此请确保在读取之前检查缓存文件是否存在。
要在其中一个目录中创建新文件,可以使用 File() 构造函数,传递上述方法之一提供的File对象,该方法指定内部存储目录。 例如:
使用外部存储非常适合您要与其他应用共享或允许用户使用计算机访问的文件。
在请求存储权限并验证存储可用后,您可以保存两种不同类型的文件:
要写入公共外部存储,您必须在清单文件中请求 WRITE_EXTERNAL_STORAGE 权限:
如果您的应用只需要读取外部存储(但不能写入),那么您需要声明 READ_EXTERNAL_STORAGE 权限:
从Android 4.4(API级别19)开始,在应用程序的私有外部存储目录中读取或写入文件(使用 getExternalFilesDir() 访问)不需要 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 权限。 因此,如果您的应用支持Android 4.3(API级别18)及更低版本,并且您只想访问专用外部存储目录,则应通过添加maxSdkVersion属性声明仅在较低版本的Android上请求权限:
由于外部存储可能不可用 - 例如当用户将存储装置安装到PC或已移除提供外部存储的SD卡时 - 您应始终在访问之前验证该卷是否可用。 您可以通过调用 getExternalStorageState() 来查询外部存储状态。 如果返回的状态为 MEDIA_MOUNTED ,则可以读取和写入文件。 如果是 MEDIA_MOUNTED_READ_ONLY ,则只能读取文件。
例如,以下方法可用于确定存储可用性:
如果要将公共文件保存在外部存储上,请使用 getExternalStoragePublicDirectory() 方法获取表示外部存储上相应目录的File。 该方法接受一个参数,指定要保存的文件类型,以便可以使用其他公共文件(如 DIRECTORY_MUSIC 或 DIRECTORY_PICTURES )对其进行逻辑组织。 例如:
如果要从Media Scanner中隐藏文件,请在外部文件目录中包含名为.nomedia的空文件(请注意文件名中的点前缀)。 这可以防止媒体扫描程序读取您的媒体文件,并通过MediaStore内容提供商将其提供给其他应用程序。
如果要将文件保存在应用程序专用的外部存储上且MediaStore内容提供程序无法访问,您可以通过调用 getExternalFilesDir() 并向其传递一个指示目录类型的名称来获取仅由您的应用程序使用的目录。 你想。 以这种方式创建的每个目录都会添加到父目录中,该目录封装了应用程序的所有外部存储文件,系统会在用户卸载应用程序时将其删除。
例如,这是一种可用于为单个相册创建目录的方法:
如果没有预定义的子目录名称适合您的文件,则可以调用 getExternalFilesDir() 并传递null。 这将返回外部存储上应用程序私有目录的根目录。
请记住, getExternalFilesDir() 会创建一个在用户卸载应用程序时删除的目录。 如果您保存的文件在用户卸载应用程序后仍然可用 - 例如当您的应用程序捕获照片并且用户应保留这些照片时 - 您应该将文件保存到公共目录。
无论您对共享文件使用 getExternalStoragePublicDirectory() 还是对应用程序专用的文件使用 getExternalFilesDir() ,都必须使用API常量(如 DIRECTORY_PICTURES )提供的目录名称。 这些目录名称可确保系统正确处理文件。 例如,保存在 DIRECTORY_RINGTONES 中的文件被系统媒体扫描仪分类为铃声而不是音乐。
有时,分配内部存储器分区以用作外部存储器的设备也提供SD卡插槽。 这意味着该设备有两个不同的外部存储目录,因此您需要选择在将“私有”文件写入外部存储时使用哪个目录。
从Android 4.4(API级别19)开始,您可以通过调用 getExternalFilesDirs() 来访问这两个位置,该方法返回一个文件数组,其中包含每个存储位置的条目。 阵列中的第一个条目被视为主要外部存储,您应该使用该位置,除非它已满或不可用。
如果您的应用支持Android 4.3及更低版本,则应使用支持库的静态方法 ContextCompat.getExternalFilesDirs() 。 这总是返回一个文件阵列,但如果设备运行的是Android 4.3及更低版本,那么它只包含一个主外部存储条目(如果有第二个存储位置,则无法在Android 4.3及更低版本上访问它)。
如果您提前知道要保存多少数据,则可以通过调用 getFreeSpace() 或 getTotalSpace() 来确定是否有足够的空间可用而不会导致IOException。 这些方法分别提供当前可用空间和存储卷中的总空间。 此信息对于避免将存储卷填充到某个阈值以上也很有用。
但是,系统不保证您可以写入 getFreeSpace() 指示的字节数。 如果返回的数字比您要保存的数据大小多几MB,或者文件系统小于90%已满,则可以继续。 否则,您可能不应该写入存储。
您应该始终删除应用不再需要的文件。 删除文件最直接的方法是在File对象上调用 delete() 。
如果文件保存在内部存储器上,您还可以通过调用 deleteFile() 来请求Context查找并删除文件:
Python面向对象之文件操作
文件的概念
文件的概念和作用
- 计算机的文件,就是存储在某种长期存储设备上的一段数据;长期存储设备包括:U盘,硬盘,移动硬盘,光盘,等;
- 文件的作用:将数据长期保存,在需要的时候使用;
文件的存储方式
在计算机中,文件是以二进制的形式保存在磁盘上的;
文本文件和二进制文件
文本文件
- 可以用文本编辑软件查看;
- 本质上还是二进制文件;
例如:python源文件。
二进制文件
- 保存的文件不是直接给人阅读的,而是提供给其他软件使用的;
- 二进制文件不能会用文本编辑软件查看;
例如:图片文件,音频文件等
文件的基本操作
文件操作步骤
在计算机中操作文件的步骤时分固定,一共包含三个步骤:
- 打开文件;
- 读,写文件;读:将文本内容读入内存;写:将内存内容写入文本;
- 关闭文件;
操作文件的方法/函数
在python中操作文件需要记住一个函数和两个方法
序号 | 函数/方法 | 说明 |
---|---|---|
1 | open | 打开文件,返回文件操作对象; |
2 | read | 将文件内容读取到内存; |
3 | write | 将指定内容写入到文件; |
4 | close | 关闭文件; |
- open函数负责打开文件,返回文件操作对象;
- 其余三个方法需要通过文件对象调用;
read方法-读取文件
open函数的第一个参数是要打开的文件名(文件名区分大小写);
如果文件存在,返回文件操作对象
如果文件不存在,会抛出异常
read方法可以一次性读入并返回文件的所有内容;
close方法负责关闭文件;
如果忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问;
注意:read方法执行后,会把文件指针移动到文件的末尾;
提示:在开发中,通常会先编写打开和关闭的代码,再编写中间针对文件的读写操作;
读取文件示例
# 打开文件
file = open("hello.txt")
# 读取文件
text = file.read()
print(text)
# 关闭文件
file.close()
# welcome to hello.txt
# this is a test file.
文件指针
- 文件指针标识 从哪个位置开始读取数据;
- 第一次打开文件时,通常文件指针会指向文件的开始位置;
- 当执行了read方法后,文件指针会移动到读取内容的末尾;默认情况下会移动到文件末尾;
所以,如果在同一次打开文件中,执行了一次read方法,读取所有内容,再次调用read方法的话,就不能够再获得内容了;这是因为第一次读取之后,文件指针移动到了文件末尾,再次调用不会读取到任何的内容;
文件指针示例
# 打开文件
file = open("hello.txt")
# 读取文件
text = file.read()
print(text)
print(len(text))
print("-"*50)
# 再次读取文件
text1 = file.read()
print(text1)
print(len(text1))
# 关闭文件
file.close()
# welcome to hello.txt
# this is a test file.
# 42
# --------------------------------------------------
# 0
open函数-打开文件的方式
open函数默认以只读方式打开文件,并且返回文件对象
open函数语法如下:
f = open("文件名", "访问方式")
open打开文件情况罗列
访问方式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常 |
w | 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a | 以追加方式打开文件。如果文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入。 |
r+ | 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常。 |
w+ | 以读写方式打开文件。如果文件村子会被覆盖。如果文件不存在,创建新文件。 |
a+ | 以读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入。 |
打开方式其实还有"rb","wb","wb+",...等,这是针对二进制文件的方式。
提示
- 频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候会以只读,只写的方式来操作文件。
追写文件示例
file = open("hello.txt", "a")
file.write("hello world")
file.close()
按行读取文件内容
- read方法默认会把文件的所有内容一次性读取到内存;
- 如果文件太大,对内存的占用会非常严重。
readline方法
- readline方法可以一次读取一行内容;
- 方法执行后,会把文件指针移动到下一行,准备再次读取;
读取指定行数数据
file = open("hello.txt")
line1 = file.readline()
print(line1)
line2 = file.readline()
print(line2)
file.close()
# 1.welcome to hello.txt
# 2.this is a test file.
分行读取整个文件:
hello.txt内容
1.welcome to hello.txt
2.this is a test file.
3.hello world
readline_test.py内容
file = open("hello.txt")
while 1:
line = file.readline()
print(line, end="")
if not line:
break
file.close()
# 运行结果
# 1.welcome to hello.txt
# 2.this is a test file.
# 3.hello world
小文件复制示例
# 打开文件
read_file = open("hello.txt")
write_file = open("hello_small.txt", "w")
# 读写文件
text = read_file.read()
write_file.write(text)
# 关闭文件
read_file.close()
write_file.close()
大文件复制示例
# 打开文件
read_file = open("hello.txt")
write_file = open("hello_big.txt", "w")
# 读写文件
while 1:
# 读取一行内容
text = read_file.readline()
# 判断是否有内容
if not text:
break
# 写入复制文件
write_file.write(text)
# 关闭文件
read_file.close()
write_file.close()
文件/目录的常用管理操作
- 在终端/文件浏览器中,可以执行常规的文件/目录管理操作,例如:创建,重命名,删除,改变路径,查看目录内容等等。
- 在Python中,如果希望通过程序实现上述功能,需要导入os模块。
文件操作方法罗列
序号 | 方法名 | 说明 | 示例 |
---|---|---|---|
01 | rename | 重命名文件 | os.rename(源文件名,目标文件名) |
02 | remove | 删除文件 | os.remove(文件名) |
目录操作方法罗列
序号 | 方法名 | 说明 | 示例 |
---|---|---|---|
01 | listdir | 目录列表 | os.listdir(目录名) |
02 | mkdir | 创建目录 | os.mkdir(目录名) |
03 | rmdir | 删除目录 | os.rmdir(目录名) |
04 | getcwd | 获取当前目录 | os.getcwd() |
05 | chdir | 修改工作目录 | os.chdir(目标目录) |
06 | path.isdir | 判断是否是文件 | os.path.isdir(文件路径) |
提示:文件/目录操作都支持绝对路径/相对路径
文本文件的编码格式
- 文本文件存储的内容是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等;
- python2.x默认使用ASCII编码;
- python3.x默认使用UTF-8编码;
ASCII编码和UNICODE编码
ASCII编码
- 计算机中只有256个ASCII字符;
- 一个ASCII在内存中占用1个字节的空间;而8个0/1的排列组合方式一共有256中,也就是2**8
UTF-8编码
- 计算机中使用的1-6个字节来表示一个utf-8字节,涵盖了地球上几乎所有地区的文字;
- 大多数汉字会使用3个字节来表示;
- utf-8是UNICODE编码的一种编码格式。
python2.x中使用中文
在python2.x文件的第一行增加以下代码,解释器会以utf-8编码来处理python文件;
# *-* coding:utf8 *-*
上面这种是官方推荐使用的,也可以使用下面这种方式:
# coding=utf8
unicode字符串前加u
- 在python2.x中,即使指定了文件使用utf-8的编码格式,但是在遍历字符串时,仍然会以字节为单位遍历字符串;
- 要能够正确的遍历字符串,在定义字符串时,需要在字符串的引号前,增加一个小写字母u,告诉解释器这是一个unicode字符串(使用utf-8编码格式的字符串)。
例如下面的代码:
test_str = "hello世界"
print(test_str)
在2和3下都会正确执行,但是当我们遍历输出字符串时,就会出现不一样的情况;
test_str = "hello世界"
print(test_str)
for i in test_str:
print(i)
在python3中可以正常执行以上代码;
但是在python2中,可以输出完整字符,遍历时输出的结果中"世界"显示的是六行特殊字符;
解决为 定义字符串时,需要在字符串的引号前,增加一个小写字母u。
示例如下:
test_str = u"hello世界"
print(test_str)
for i in test_str:
print(i)
以上是关于将文件保存在设备存储上的主要内容,如果未能解决你的问题,请参考以下文章