Android Json文件解析及带关键字文件解压
Some problems encountered and their answers in work (Android Chapter)
Android 如何解析一个.json文件
在Android中,我们通常使用JSON格式来与后端服务器通信,需要解析JSON数据来提取有用的信息。解析JSON数据通常分为两个阶段:首先将JSON数据解析为JSON对象或JSON数组,然后从中提取所需的信息。
以下是一个简单的示例,演示如何解析一个本地JSON文件:
假设我们有一个名为"example.json"的本地JSON文件,它包含以下内容:
json
{
"name": "John Smith",
"age": 35,
"isMarried": true,
"hobbies": [
"reading",
"fishing",
"hiking"
]
}
我们可以使用Android中的JSON API来解析这个文件。以下是一些示例代码,假设我们希望从JSON文件中提取姓名和年龄:
import org.json.JSONObject
import java.io.BufferedReader
import java.io.InputStreamReader
// 读取JSON文件并创建JSON对象
val inputStream = resources.assets.open("example.json")
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
val jsonString = bufferedReader.use { it.readText() }
val jsonObject = JSONObject(jsonString)
// 从JSON对象中提取所需信息
val name = jsonObject.getString("name")
val age = jsonObject.getInt("age")
在上述代码片段中,我们首先打开example.json文件,并逐行读取它的内容。然后,我们使用JSON字符串创建一个JSON对象,然后从中提取出需要的数据。在本例中,我们使用了getString()和getInt()方法来提取字符串和整数类型的值。这些方法的参数是JSON键(key),它们指定需要提取的值所在的位置。
请注意,这个示例假设example.json文件位于app/src/main/assets/目录下。如果文件位于其他目录下,需要相应地更改路径。
在/storage/7EE2-7093/目录下有一个partNumber.json文件,此json文件的内容为:
{
"partnum": [{
"value": "703000555AA"
},
{
"value": "703000555AG"
},
{
"value": "703000555AT"
},
{
"value": "703000555AH"
}
]
}
在Android程序中我如何解析此json文件获取到每个value后面的值
1. 读取partNumber.json文件的内容并转换为字符串。
try {
InputStream is = new FileInputStream(new File("/storage/7EE2-7093/partNumber.json"));
int size = is.available();
byte buffer[] = new byte[size];
is.read(buffer);
is.close();
String json = new String(buffer, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
2. 解析JSON字符串并获取value对应的值。
try {
JSONObject jsonObject = new JSONObject(json);
JSONArray partNumArray = jsonObject.getJSONArray("partnum");
for (int i = 0; i < partNumArray.length(); i++) {
JSONObject partNumObject = partNumArray.getJSONObject(i);
String value = partNumObject.getString("value");
// 在这里对每个value进行操作
}
} catch (JSONException e) {
e.printStackTrace();
}
在上面的代码中,先将partNumber.json文件的内容读取为字符串,然后使用JSONObject将其转换为JSON对象。接着,获取JSON对象中的partnum数组,并遍历该数组中的每个元素。对于每个元素,使用getJSONObject方法获取包含value字段的JSON对象,并使用getString方法获取value对应的值。最后,可以对每个value进行操作或将其存储到一个数组或列表中。
注意要在AndroidManifest.xml文件中添加读取外部存储权限: `<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />`
有一个parNum.json文件需要存放在Android Studio项目中并读取他,应该如何存放并读取
要在Android Studio项目中存储和读取parNum.json文件,可以将该文件放置在项目的assets目录中。
1. 创建assets目录:
如果项目中没有assets目录,可以手动创建一个。在项目根目录中右键单击,选择New -> Folder -> Assets Folder,然后命名为“assets”并点击Finish。
2. 存储parNum.json文件:
将parNum.json文件复制到assets目录中。在资源管理器中找到该文件,右键单击并选择Copy,然后在Android Studio中的assets目录中右键单击并选择Paste即可。
3. 读取parNum.json文件:
要读取该文件,可以使用以下代码:
import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
import org.json.JSONException;
import org.json.JSONObject;
public class Utils {
public static JSONObject getJSON(Context context, String filename) {
String jsonString;
try {
InputStream is = context.getAssets().open(filename);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
jsonString = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
try {
JSONObject jsonObject = new JSONObject(jsonString);
return jsonObject;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
}
这个 `getJSON()` 方法将从传入的上下文中的assets目录中获取文件名对应的文件,并返回一个包含JSON数据的JSONObject对象。在您的活动中使用该方法,例如:
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONObject;
public class MainActivity extends AppCompatActivity {
private JSONObject parNum;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parNum = Utils.getJSON(this, "parNum.json");
if (parNum == null) {
// 处理获取json文件失败的情况
} else {
// 处理获取json文件成功的情况
}
}
}
这样,您就可以将parNum.json文件存储在Android Studio项目中并从中读取它了。
在Android Studio名叫ReadJsonTest项目中创建一个jsonFile的文件夹,文件夹内存放一个partNum.json的文件,在代码中如何读取partNum.json文件
您可以使用以下代码在Android Studio中读取名为partNum.json的文件:
try {
InputStream is = getAssets().open("jsonFile/partNum.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String json = new String(buffer, "UTF-8");
// 处理 json 字符串...
} catch (IOException ex) {
ex.printStackTrace();
}
在这个示例中,我们使用 `getAssets().open()` 方法打开位于 `jsonFile/partNum.json` 相对路径的文件,并通过 `InputStream` 对象读取该文件。然后,我们将读取的数据转换为字符串格式,并最终处理该字符串中的JSON数据。
需要注意的是,这段代码假定您已经创建了名为 `jsonFile` 的文件夹,并在其中存放了 `partNum.json` 文件。如果您没有这样做,请先创建该文件夹并将文件存放在其中,然后再使用以上代码读取文件。
Android 项目中外部文件必须放在assets文件夹里面吗,有其他替代的方法吗‘
在Android项目中,您可以将外部文件放在其他位置,例如res/raw目录或磁盘上的任何位置,但是使用这些文件时需要使用不同的方法。以下是一些替代方法:
1. Res/raw目录:将文件放在res/raw目录下,并使用以下代码读取文件:
InputStream is = getResources().openRawResource(R.raw.filename);
2. 磁盘上的任何位置:将文件放在磁盘上的任何位置,并使用以下代码读取文件:
File file = new File("/path/to/file");
InputStream is = new FileInputStream(file);
需要注意的是,在使用这些方法时,您需要获取正确的文件路径,并在读取文件时处理可能会发生的异常。此外,如果您需要在应用程序升级后更改文件,则需要考虑将文件放在外部存储设备上,并在运行时请求适当的权限来访问该设备。
解压文件(可解压包含某关键字文件)
fun unzipFileByKeyword(zipFile: File?, destDir: File?, keyword: String?): List<File>? {
if (zipFile == null || destDir == null) return null
val files: ArrayList<File> = ArrayList()
val zip = ZipFile(zipFile)
val entries: Enumeration<*> = zip.entries()
try {
if (isSpace(keyword)) {
while (entries.hasMoreElements()) {
val entry = entries.nextElement() as ZipEntry
val entryName = entry.name.replace("\\", "/")
if (entryName.contains("../")) {
Log.e("ZipUtils", "entryName: $entryName is dangerous!")
continue
}
if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files
}
} else {
while (entries.hasMoreElements()) {
val entry = entries.nextElement() as ZipEntry
val entryName = entry.name.replace("\\", "/")
if (entryName.contains("../")) {
Log.e("ZipUtils", "entryName: $entryName is dangerous!")
continue
}
if (entryName.contains(keyword!!)) {
if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files
}
}
}
}catch (e:Exception){
e.printStackTrace()
} finally {
zip.close()
}
return files
}
@Throws(IOException::class)
private fun unzipChildFile(destDir: File, files: ArrayList<File>, zip: ZipFile, entry: ZipEntry, name: String): Boolean {
val file = File(destDir, name)
files.add(file)
if (entry.isDirectory) {
return createOrExistsDir(file)
} else {
if (!createOrExistsFile(file)) return false
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
try {
inputStream = BufferedInputStream(zip.getInputStream(entry))
outputStream = BufferedOutputStream(FileOutputStream(file))
val buffer = ByteArray(8192)
var len: Int
while (inputStream.read(buffer).also { len = it } != -1) {
outputStream.write(buffer, 0, len)
}
} finally {
inputStream?.close()
outputStream?.close()
}
}
return true
}
将以上代码进行优化后
fun unzipFileByKeyword(zipFile: File?, destDir: File?, keyword: String?): List<File>? {
if (zipFile == null || destDir == null) return null
if (!destDir.exists() || !destDir.isDirectory) return null
val files: MutableList<File> = mutableListOf()
val zip = ZipFile(zipFile)
try {
val entries = zip.entries().asSequence().filter { !it.isDirectory && (keyword == null || it.name.contains(keyword)) }
entries.forEach { entry ->
val entryName = entry.name.replace("\\", "/")
if (entryName.contains("../")) {
Log.e("ZipUtils", "entryName: $entryName is dangerous!")
return@forEach
}
val file = File(destDir, entryName)
if (!createOrExistsFile(file)) return@forEach
zip.getInputStream(entry)?.use { inputStream ->
BufferedOutputStream(FileOutputStream(file)).use { outputStream ->
inputStream.copyTo(outputStream)
}
}
files.add(file)
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
zip.close()
}
return files
}
fun createOrExistsDir(file: File): Boolean {
return if (file.exists()) {
file.isDirectory
} else {
file.mkdirs()
}
}
fun createOrExistsFile(file: File): Boolean {
if (file.exists()) return file.isFile
if (!createOrExistsDir(file.parentFile)) return false
return try {
file.createNewFile()
} catch (e: IOException) {
e.printStackTrace()
false
}
}
zip.entries().asSequence().filter ===>
这段代码返回一个Sequence<ZipEntry>对象,它包含.zip文件中的所有条目(entries)。具体地说,它使用.entries()方法获取所有的条目,并将它们作为Sequence对象返回。然后,使用asSequence()方法将此Sequence转换为另一个Sequence对象,以便后续操作。接下来,使用filter()方法对转换后的Sequence中的条目进行过滤。这个方法使用一个lambda表达式来指定过滤条件。在这个例子中,过滤条件是ZipEntry对象的名称(name)属性以某个特定字符串结尾。最后,返回的Sequence对象包含所有满足过滤条件的条目。
val entries = zip.entries().asSequence().filter {
!it.isDirectory && (keyword == null || it.name.contains(keyword))
} ===>
这段代码的返回值是一个经过筛选的ZipEntry对象的Sequence序列。其中每个ZipEntry对象都满足以下两个条件之一:
1.它的名称(name)属性以指定的关键字(keyword)结尾(如果指定了关键字)。
2.它不是一个目录(isDirectory属性为false)。
这个Sequence序列中的每个对象都表示.zip文件中的一个文件或目录。
1.将返回类型更改为MutableList<File>,而不是可为null的List<File>。
2.添加了一个检查,以确保目标目录存在并且是一个目录。
3.使用Kotlin的asSequence()函数将Enumeration转换为Sequence。
4.使用use功能自动处理关闭的流和文件。
5.删除了两次检查关键字的多余if语句。
6.将用于创建文件或目录的代码提取到单独的函数中。
7.将ArrayList更改为MutableList,以允许使用Kotlin的可变列表函数。
8.删除了不必要的变量声明(例如inputStream、outputStream、len)。
9.使用copyTo()函数将字节从输入流复制到输出流。
10.将ArrayList更改为MutableList,以允许使用Kotlin的可变列表函数。
以上代码中keyword如何使用
这段代码中的"keyword"是一个可选的参数,用于过滤zip文件中的条目。如果传递了"keyword"参数,则只有那些名称中包含它的条目才会被提取。如果未传递"keyword"参数,则所有条目都会被提取。此处的关键字是一个字符串类型的变量,可以在函数调用时作为参数传递,例如:
val extractedFiles = unzipFileByKeyword(zipFile, destDir, "example")
这将用"example"作为关键字来提取zip文件中名称中包含"example"的条目,并将结果存储在"extractedFiles"列表中。如果您不想使用关键字,请将其设置为null,例如:
val extractedFiles = unzipFileByKeyword(zipFile, destDir, null)
这将提取zip文件中的所有条目,而不考虑名称。