如何将SharedPreferences备份到SD卡?

21

我在很多地方看到这样一个问题:将SharedPreferences文件复制到SD卡上是个问题,因为每个制造商都将它放在不同的位置。

我想要将其备份到SD卡,无论该文件位于何处。 有没有什么方法可以做到这一点?

4个回答

53

SharedPreferences接口包含一个名为getAll()的方法,该方法返回一个带有键值对的映射。因此,我不需要复制文件本身,而是将从此方法返回的映射进行序列化,然后在之后检索它。

一些代码:

private boolean saveSharedPreferencesToFile(File dst) {
    boolean res = false;
    ObjectOutputStream output = null;
    try {
        output = new ObjectOutputStream(new FileOutputStream(dst));
        SharedPreferences pref = 
                            getSharedPreferences(prefName, MODE_PRIVATE);
        output.writeObject(pref.getAll());

        res = true;
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            if (output != null) {
                output.flush();
                output.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    return res;
}

@SuppressWarnings({ "unchecked" })
private boolean loadSharedPreferencesFromFile(File src) {
    boolean res = false;
    ObjectInputStream input = null;
    try {
        input = new ObjectInputStream(new FileInputStream(src));
            Editor prefEdit = getSharedPreferences(prefName, MODE_PRIVATE).edit();
            prefEdit.clear();
            Map<String, ?> entries = (Map<String, ?>) input.readObject();
            for (Entry<String, ?> entry : entries.entrySet()) {
                Object v = entry.getValue();
                String key = entry.getKey();

                if (v instanceof Boolean)
                    prefEdit.putBoolean(key, ((Boolean) v).booleanValue());
                else if (v instanceof Float)
                    prefEdit.putFloat(key, ((Float) v).floatValue());
                else if (v instanceof Integer)
                    prefEdit.putInt(key, ((Integer) v).intValue());
                else if (v instanceof Long)
                    prefEdit.putLong(key, ((Long) v).longValue());
                else if (v instanceof String)
                    prefEdit.putString(key, ((String) v));
            }
            prefEdit.commit();
        res = true;         
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }finally {
        try {
            if (input != null) {
                input.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    return res;
}

我希望我的回答能够对某人有所帮助,如果有不正确的地方,请告诉我。

Elad


请问为什么我在使用你的代码时会遇到这个问题:http://stackoverflow.com/questions/23535545/android-cannot-use-entry-entryset - Dev01
Entry<String, ?> entry 给我: "类型 DropBoxManager.Entry 不是泛型;无法使用参数 <String,?>"。 - Matan
谢谢,这比我预想的要难得多。这个解决方案是最好的。我不得不稍微修改一下文件处理,但它现在运行得非常好。 - midiwriter
如果您发布您的工作代码以帮助他人而不是为自己保留,那将是很好的。 - Frank

4
File ff = new File("/data/data/"
                            + MainActivity.this.getPackageName()
                            + "/shared_prefs/pref file name.xml");

                    Log.i("ddddddddddddd", ff.getPath() + "");

                    copyFile(ff.getPath().toString(), sdcard path/save file name.xml");

private void copyFile(String filepath, String storefilepath) {
    try {
        File f1 = new File(filepath);
        File f2 = new File(storefilepath);
        InputStream in = new FileInputStream(f1);

        OutputStream out = new FileOutputStream(f2);

        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
        System.out.println("File copied.");
    } catch (FileNotFoundException ex) {
        System.out.println(ex.getMessage());

    } catch (IOException e) {
        System.out.println(e.getMessage());
    }

}

1
这是获取 XML 文件的精确副本的好方法,但也许最好不要硬编码 /data 路径,而是使用 Context.getFilesDir().getPath()。 - Pelanes

3

除了使用ObjectOutputStream/ObjectInputStream,您还可以将Android源代码中的XmlUtils.java和FastXmlSerializer.java文件添加到您的项目中,然后使用XmlUtils.writeMapXml()和XmlUtils.readMapXml():

boolean res = false;
FileOutputStream output = null;
try {
    output = new FileOutputStream(dst);
    SharedPreferences pref = 
                        getSharedPreferences(prefName, MODE_PRIVATE);
    XmlUtils.writeMapXml(pref.getAll(), output);

    res = true;
    }

.....

FileInputStream input = null;
try {
    input = new FileInputStream(src);
        Editor prefEdit = getSharedPreferences(prefName, MODE_PRIVATE).edit();
        prefEdit.clear();
        Map<String, ?> entries = XmlUtils.readMapXml(input);
        for (Entry<String, ?> entry : entries.entrySet()) {
            putObject(prefEdit, entry.getKey(), entry.getValue());
        }
    }

.....

static SharedPreferences.Editor putObject(final SharedPreferences.Editor edit,
                                          final String key, final Object val) {
    if (val instanceof Boolean)
        return edit.putBoolean(key, ((Boolean)val).booleanValue());
    else if (val instanceof Float)
        return edit.putFloat(key, ((Float)val).floatValue());
    else if (val instanceof Integer)
        return edit.putInt(key, ((Integer)val).intValue());
    else if (val instanceof Long)
        return edit.putLong(key, ((Long)val).longValue());
    else if (val instanceof String)
        return edit.putString(key, ((String)val));

    return edit;
}

存储格式将与用于存储SharedPreferences的XML相同。

你能发完整的第二组代码吗?它似乎不完整。 - dknchris

0
try {
    input = new FileInputStream(src1);
    SharedPreferences.Editor prefEdit =   getSharedPreferences("prueba100", MODE_PRIVATE).edit();
    prefEdit.clear();
    Map<String, ?> entries = XmlUtils.readMapXml(input);
    for (Map.Entry<String, ?> entry : entries.entrySet()) {
        putObject(prefEdit, entry.getKey(), entry.getValue());
    }
    prefEdit.apply();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (XmlPullParserException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

1
在SO中,仅提供代码的答案是不被赞同的。请包含一个解释说明您的代码如何回答问题。此外,请通过在每行代码开头放置4个空格来格式化代码。 - Kelly Keller-Heikkila

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接