我试图获取一个带有目录结构的JSON文件,包括递归的文件和子目录。
使用apache-commons-io
库我得到一个具有我想要的结构的子目录和文件列表:
List<File> files = (List<File>) FileUtils.listFilesAndDirs(
Environment.getExternalStorageDirectory(),
DirectoryFileFilter.INSTANCE,
DirectoryFileFilter.INSTANCE);
但是当我尝试使用Gson
库将其序列化为JSON文件时,返回的String只包含根路径:
Gson gson = new Gson();
String json = gson.toJson(files.get(0));
输出
{
"path": "/storage/emulated/0"
}
如何获取包含所有子目录和文件的JSON对象?
答案 0 :(得分:0)
你打印什么,得到什么:
Gson gson = new Gson();
String json = gson.toJson(files.get(0)); // one file
{
"path": "/storage/emulated/0"
}
String json = gson.toJson(files); // all files
[
{
"path": "/storage/emulated/0"
},
{
"path": "/storage/emulated/0/dir1"
},
{
"path": "/storage/emulated/dir2"
}
]
答案 1 :(得分:0)
您的问题存在多个问题。 例如,我发现的是:
files.get(0)
只返回第一个孩子。如果没有孩子,肯定会失败。DirectoryFileFilter
只接受目录,而你需要TrueFileFilter
,正如Java文档中指出的那样。LinkedList
可能是一个内存问题。例如,Google Guava fileTreeTraverser
返回遍历器,该遍历器允许迭代不需要将整个列表存储在内存中的迭代(但是它需要Iterable
的自定义序列化器/解串器对并检测目录输入/无论如何离开)。String Gson.toJson(...)
将可能较大的集合序列化为字符串是另一个内存问题。如果可能,您应该考虑流式传输。File
,因为Gson没有为它提供序列化/解串器对。从最新的Gson版本2.8.4开始,它使用ReflectiveTypeAdapterFactory$Adapter
,因此它使用File
字段。如果File
内部结构因任何原因发生更改,您将无法对其进行反序列化。此外,拥有单个path
属性不允许您区分目录和文件。说完之后,你可能想要遍历一个文件目录,自己将每个目录和文件转换成你想要消耗的任何表示形式尽可能少的文件。
以下界面允许您构建任何JSON结构。例如:
[
"./file1",
"./file2",
"./dir1",
"./dir1/file1",
"./dir1/file2",
"./dir2",
"./dir2/file1"
]
[
{"type": "file", "path": "./file1"},
{"type": "file", "path": "./file2"},
{"type": "directory", "path": "./dir1"},
{"type": "file", "path": "./dir1/file1"},
{"type": "file", "path": "./dir1/file2"},
{"type": "directory", "path": "./dir2"},
{"type": "file", "path": "./dir2/file1"}
]
null
表示文件:{
"file1": null
"file2": null,
"dir1": {
"file1": null,
"file2": null
},
"dir2": {
"file1": null
}
}
[
"file1"
"file2",
{
"name": "dir1",
"children": [
"file1",
"file2"
]
},
{
"name": "dir2",
"children": [
"file1"
]
}
]
interface IDirectoryWalkListener {
void onEnterDirectory(int level, @Nonnull File directory)
throws IOException;
void onFile(@Nonnull File file)
throws IOException;
void onLeaveDirectory(int level, @Nonnull File directory)
throws IOException;
}
final class DirectoryWalk {
private DirectoryWalk() {
}
static void walk(final File root, final IDirectoryWalkListener listener)
throws IOException {
walk(0, root, listener);
}
private static void walk(final int level, final File root, final IDirectoryWalkListener listener)
throws IOException {
if ( !root.isDirectory() ) {
throw new IOException(root + " must be a directory");
}
@Nullable
final File[] files = root.listFiles();
if ( files == null ) {
throw new IOException("Cannot list files in " + root);
}
listener.onEnterDirectory(level, root);
for ( final File file : files ) {
if ( file.isDirectory() ) {
walk(level + 1, file, listener);
} else {
listener.onFile(file);
}
}
listener.onLeaveDirectory(level, root);
}
}
final class ToFlatJsonArrayDirectoryWalkListener
implements IDirectoryWalkListener {
private final JsonWriter jsonWriter;
private ToFlatJsonArrayDirectoryWalkListener(final JsonWriter jsonWriter) {
this.jsonWriter = jsonWriter;
}
static IDirectoryWalkListener get(final JsonWriter jsonWriter) {
return new ToFlatJsonArrayDirectoryWalkListener(jsonWriter);
}
@Override
public void onEnterDirectory(final int level, @Nonnull final File directory)
throws IOException {
if ( level == 0 ) {
jsonWriter.beginArray();
}
jsonWriter.value(directory.getPath());
}
@Override
public void onFile(@Nonnull final File file)
throws IOException {
jsonWriter.value(file.getPath());
}
@Override
public void onLeaveDirectory(final int level, @Nonnull final File directory)
throws IOException {
if ( level == 0 ) {
jsonWriter.endArray();
}
}
}
使用示例:
// Writing to a string is a potential performance and memory issue
final Writer out = new StringWriter();
final JsonWriter jsonWriter = new JsonWriter(out);
jsonWriter.setIndent("\t");
DirectoryWalk.walk(root, ToFlatJsonArrayDirectoryWalkListener.get(jsonWriter));
System.out.println(out);
final Writer out = new OutputStreamWriter(System.out) {
@Override
public void close() {
// do not close System.out
}
};
final JsonWriter jsonWriter = new JsonWriter(out);
jsonWriter.setIndent("\t");
DirectoryWalk.walk(root, ToFlatJsonArrayDirectoryWalkListener.get(jsonWriter));
out.flush();
root
为./target
的示例输出:
[
"./target",
"./target/data",
"./target/data/journal",
"./target/data/journal/server.lock",
"./target/classes",
"./target/classes/com",
"./target/classes/com/google",
"./target/classes/com/google/gson",
"./target/classes/com/google/gson/interceptors",
"./target/classes/com/google/gson/interceptors/InterceptorFactory$InterceptorAdapter.class",
"./target/classes/com/google/gson/interceptors/InterceptorFactory$1.class",
"./target/classes/com/google/gson/interceptors/InterceptorFactory.class",
"./target/classes/com/google/gson/interceptors/JsonPostDeserializer.class",
"./target/classes/com/google/gson/interceptors/Intercept.class",
...
]
为了从JSON恢复文件结构,您需要JsonReader
(以更有效的方式使用内存)或自定义反序列化器(如果您可以将所有内容读入内存)。< / p>