如何将map写入文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将map写入文件相关的知识,希望对你有一定的参考价值。

比较简单的方法是引入json包,将map数据转换成json格式数据并存放到文件中。具体代码不在此写了。

其他的方法也可以转换成xml格式的数据,保存到内存中,不如json方法简单。另外,如果map中包含数据格式确定,可以自己写代码转换成自己定义的格式保存到文件中,该方法可修改性比较差,费时耗力。
参考技术A 代码:

using std::map;
using std::ofstream;
using std::ifstream;

map<int, int> m = ... ; // 待存储的map m

// 存入文件out.txt
ofstream of("out.txt");
for (const auto &i : m)
of << i.first << ' ' << i.second << std::endl;


// 读取文件,存入map m2中
map<int, int> m2;
ifstream if("out.txt");
int key, value;
while (if >> key >> value)
m2[key] = value;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<fstream>
#include<string>
#include<map>
#include<utility>
using namespace std;
int main()
map<int ,string> my_map;
string word;
int count=0;
cout<<"请输入字符串数据"<<endl;
while(count!=4)
cin>>word ;
my_map.insert(make_pair(++count,word));

//读入文本
ifstream ins("text.txt");
ofstream ous("text.txt");
map<int ,string>::iterator iter=my_map.begin();
for(;iter!=my_map.end();iter++)
ous<<iter->first<<" "<<iter->second<<endl;

//从文本中读出
map<int ,string> your_map;
while(!ins.eof())
int key;
string value;
ins>>key>>value;
your_map.insert(make_pair(key,value));

for(map<int,string>::iterator itr=your_map.begin();itr!=your_map.end();itr++)
cout<<"The "<<itr->first<<"th word is"<<itr->second<<endl;


return 0;

如何以智能的方式将 Java.util.Map 写入包裹?

【中文标题】如何以智能的方式将 Java.util.Map 写入包裹?【英文标题】:How write Java.util.Map into parcel in a smart way? 【发布时间】:2012-01-05 11:32:23 【问题描述】:

我有一个字符串(键、值)的通用映射,这个字段是我需要打包的 Bean 的一部分。 所以,我可以使用 Parcel#writeMap 方法。 API 文档说:

请改用 writeBundle(Bundle)。将地图展平到地块中 在当前 dataPosition() 处,如果需要,增加 dataCapacity()。这 映射键必须是字符串对象。地图值是使用编写的 writeValue(Object) 并且必须遵循那里的规范。它是 强烈建议使用 writeBundle(Bundle) 而不是这个 方法,因为 Bundle 类提供了一个类型安全的 API,它允许 您可以避免在编组时出现神秘的类型错误。

所以,我可以遍历 Map 中的每个条目,并将其放入 Bundle,但我仍在寻找更智能的方法。我缺少 Android SDK 中的任何方法吗?

目前我是这样做的:

final Bundle bundle = new Bundle();
final Iterator<Entry<String, String>> iter = links.entrySet().iterator();
while(iter.hasNext())

    final Entry<String, String>  entry =iter.next();
    bundle.putString(entry.getKey(), entry.getValue());

parcel.writeBundle(bundle);

【问题讨论】:

我已提议对 api 报价进行修改。现在水平滚动阅读它很不舒服。 您找到解决此问题的方法了吗?如果是这样,请在此处发布您的解决方案或选择最佳答案。 【参考方案1】:

你可以试试:

bundle.putSerializable(yourSerializableMap);

如果您选择的地图实现了可序列化(如 HashMap),那么您可以轻松使用您的 writeBundle

【讨论】:

它可能不是最好的,效率方面,但肯定写起来很短:)【参考方案2】:

好问题。除了 putSerializable 和 writeMap 之外,我所知道的 API 中没有任何方法。出于性能原因,序列化是not recommended,并且正如您已经指出的那样,由于有些神秘的原因也不推荐使用 writeMap()。

我今天需要打包一个 HashMap,所以我尝试编写一些实用方法,以推荐的方式将 Map 与 Bundle 打包:

// Usage:

// read map into a HashMap<String,Foo>
links = readMap(parcel, Foo.class);

// another way that lets you use a different Map implementation
links = new SuperDooperMap<String, Foo>;
readMap(links, parcel, Foo.class);

// write map out
writeMap(links, parcel);

////////////////////////////////////////////////////////////////////
// Parcel methods

/**
 * Reads a Map from a Parcel that was stored using a String array and a Bundle.
 *
 * @param in   the Parcel to retrieve the map from
 * @param type the class used for the value objects in the map, equivalent to V.class before type erasure
 * @return     a map containing the items retrieved from the parcel
 */
public static <V extends Parcelable> Map<String,V> readMap(Parcel in, Class<? extends V> type) 

    Map<String,V> map = new HashMap<String,V>();
    if(in != null) 
        String[] keys = in.createStringArray();
        Bundle bundle = in.readBundle(type.getClassLoader());
        for(String key : keys)
            map.put(key, type.cast(bundle.getParcelable(key)));
    
    return map;



/**
 * Reads into an existing Map from a Parcel that was stored using a String array and a Bundle.
 *
 * @param map  the Map<String,V> that will receive the items from the parcel
 * @param in   the Parcel to retrieve the map from
 * @param type the class used for the value objects in the map, equivalent to V.class before type erasure
 */
public static <V extends Parcelable> void readMap(Map<String,V> map, Parcel in, Class<V> type) 

    if(map != null) 
        map.clear();
        if(in != null) 
            String[] keys = in.createStringArray();
            Bundle bundle = in.readBundle(type.getClassLoader());
            for(String key : keys)
                map.put(key, type.cast(bundle.getParcelable(key)));
        
    



/**
 * Writes a Map to a Parcel using a String array and a Bundle.
 *
 * @param map the Map<String,V> to store in the parcel
 * @param out the Parcel to store the map in
 */
public static void writeMap(Map<String,? extends Parcelable> map, Parcel out) 

    if(map != null && map.size() > 0) 
        /*
        Set<String> keySet = map.keySet();
        Bundle b = new Bundle();
        for(String key : keySet)
            b.putParcelable(key, map.get(key));
        String[] array = keySet.toArray(new String[keySet.size()]);
        out.writeStringArray(array);
        out.writeBundle(b);
        /*/
        // alternative using an entrySet, keeping output data format the same
        // (if you don't need to preserve the data format, you might prefer to just write the key-value pairs directly to the parcel)
        Bundle bundle = new Bundle();
        for(Map.Entry<String, ? extends Parcelable> entry : map.entrySet()) 
            bundle.putParcelable(entry.getKey(), entry.getValue());
        

        final Set<String> keySet = map.keySet();
        final String[] array = keySet.toArray(new String[keySet.size()]);
        out.writeStringArray(array);
        out.writeBundle(bundle);
        /**/
    
    else 
        //String[] array = Collections.<String>emptySet().toArray(new String[0]);
        // you can use a static instance of String[0] here instead
        out.writeStringArray(new String[0]);
        out.writeBundle(Bundle.EMPTY);
    

编辑: 修改 writeMap 以使用 entrySet,同时保留与我的原始答案相同的数据格式(显示在切换注释的另一侧)。如果您不需要或不想保留读取兼容性,则在每次迭代中仅存储键值对可能会更简单,如@bcorso 和@Anthony Naddeo 的答案。

【讨论】:

您可以通过空检查地图来改善这一点,并在这种情况下使用 Bundle.empty @Kitesurfer 是的,这样可以避免构建空包(它只会使用静态实例)。使用 Bundle.empty 与 new Bundle() 相比还有其他优势吗? 不应该。我从未尝试过,但作为一个空的 Bundle,它应该是不可变的,文档对此只字未提,所以要小心一点。所以你对 GC/Runtime 有点帮助...... @Kitesurfer 感谢您的提示,我重写了 writeMap 函数来做到这一点(在这种情况下,也只需为键集编写一个空 String[0])。 使用 entrySet 而不是 keySet 应该更有效:您可以避免在映射中为每个条目查找值。【参考方案3】:

我最终做了一些不同的事情。它遵循您期望处理Parcelables 的模式,因此应该很熟悉。

public void writeToParcel(Parcel out, int flags)
  out.writeInt(map.size());
  for(Map.Entry<String,String> entry : map.entrySet())
    out.writeString(entry.getKey());
    out.writeString(entry.getValue());
  


private MyParcelable(Parcel in)
  //initialize your map before
  int size = in.readInt();
  for(int i = 0; i < size; i++)
    String key = in.readString();
    String value = in.readString();
    map.put(key,value);
  

在我的应用程序中,映射中键的顺序很重要。我使用LinkedHashMap 来保留顺序,并且这样做可以保证从Parcel 中提取密钥后以相同的顺序出现。

【讨论】:

使用 entrySet 而不是 keySet 应该更有效:您可以避免在映射中为每个条目查找值。 @MarvinLabs 是正确的。 This答案可以查看参考。【参考方案4】:

如果地图的keyvalue 都扩展Parcelable,你可以有一个非常漂亮的泛型解决方案:

代码

// For writing to a Parcel
public <K extends Parcelable,V extends Parcelable> void writeParcelableMap(
        Parcel parcel, int flags, Map<K, V > map)

    parcel.writeInt(map.size());
    for(Map.Entry<K, V> e : map.entrySet())
        parcel.writeParcelable(e.getKey(), flags);
        parcel.writeParcelable(e.getValue(), flags);
    


// For reading from a Parcel
public <K extends Parcelable,V extends Parcelable> Map<K,V> readParcelableMap(
        Parcel parcel, Class<K> kClass, Class<V> vClass)

    int size = parcel.readInt();
    Map<K, V> map = new HashMap<K, V>(size);
    for(int i = 0; i < size; i++)
        map.put(kClass.cast(parcel.readParcelable(kClass.getClassLoader())),
                vClass.cast(parcel.readParcelable(vClass.getClassLoader())));
    
    return map;

用法

// MyClass1 and MyClass2 must extend Parcelable
Map<MyClass1, MyClass2> map;

// Writing to a parcel
writeParcelableMap(parcel, flags, map);

// Reading from a parcel
map = readParcelableMap(parcel, MyClass1.class, MyClass2.class);

【讨论】:

aClass 实现 Parcelable 怎么样?因为 Parcelable 是 Android 中的接口 编译器显示错误Interfered type parameter java.lang.String for type parameter K is not within its bound, should implement android.os.Parcelable @Choletski 此错误是预期的,因为String 没有实现 Parcelable。这个解决方案只有在类型 K 和 V 都实现 Parcelable 时才有效(见第一句)。【参考方案5】:

这是我的有点简单,但到目前为止我在 Kotlin 中的实现工作。如果它不能满足一个需求,它可以很容易地修改

但不要忘记K,V 必须是 Parcelable 如果不同于通常的 String, Int,...

parcel.writeMap(map)

阅读

parcel.readMap(map)

读取过载

fun<K,V> Parcel.readMap(map: MutableMap<K,V>) : MutableMap<K,V>

    val tempMap = LinkedHashMap<Any?,Any?>()
    readMap(tempMap, map.javaClass.classLoader)

    tempMap.forEach 
        map[it.key as K] = it.value as V
    
    /* It populates and returns the map as well
       (useful for constructor parameters inits)*/
    return map

【讨论】:

你也有writeMap 的扩展名吗?【参考方案6】:

如果您的地图的键是字符串,您可以使用 Bundle,如 javadocs 中所述:

/**
 * Please use @link #writeBundle instead.  Flattens a Map into the parcel
 * at the current dataPosition(),
 * growing dataCapacity() if needed.  The Map keys must be String objects.
 * The Map values are written using @link #writeValue and must follow
 * the specification there.
 *
 * <p>It is strongly recommended to use @link #writeBundle instead of
 * this method, since the Bundle class provides a type-safe API that
 * allows you to avoid mysterious type errors at the point of marshalling.
 */
public final void writeMap(Map val) 
    writeMapInternal((Map<String, Object>) val);

于是我写了如下代码:

private void writeMapAsBundle(Parcel dest, Map<String, Serializable> map) 
    Bundle bundle = new Bundle();
    for (Map.Entry<String, Serializable> entry : map.entrySet()) 
        bundle.putSerializable(entry.getKey(), entry.getValue());
    
    dest.writeBundle(bundle);


private void readMapFromBundle(Parcel in, Map<String, Serializable> map, ClassLoader keyClassLoader) 
    Bundle bundle = in.readBundle(keyClassLoader);
    for (String key : bundle.keySet()) 
        map.put(key, bundle.getSerializable(key));
    

因此,您可以使用 Parcelable 代替 Serializable

【讨论】:

【参考方案7】:

这里提到的所有解决方案都是有效的,但没有一个是足够通用的。通常你有包含字符串、整数、浮点数等值和/或键的映射。在这种情况下,您不能使用 <... extends parcelable> 并且我不想为任何其他键/值组合编写自定义方法。对于这种情况,您可以使用以下代码:

@FunctionalInterface
public interface ParcelWriter<T> 
    void writeToParcel(@NonNull final T value,
                       @NonNull final Parcel parcel, final int flags);


@FunctionalInterface
public interface ParcelReader<T> 
    T readFromParcel(@NonNull final Parcel parcel);


public static <K, V> void writeParcelableMap(
        @NonNull final Map<K, V> map,
        @NonNull final Parcel parcel,
        final int flags,
        @NonNull final ParcelWriter<Map.Entry<K, V>> parcelWriter) 
    parcel.writeInt(map.size());

    for (final Map.Entry<K, V> e : map.entrySet()) 
        parcelWriter.writeToParcel(e, parcel, flags);
    


public static <K, V> Map<K, V> readParcelableMap(
        @NonNull final Parcel parcel,
        @NonNull final ParcelReader<Map.Entry<K, V>> parcelReader) 
    int size = parcel.readInt();
    final Map<K, V> map = new HashMap<>(size);

    for (int i = 0; i < size; i++) 
        final Map.Entry<K, V> value = parcelReader.readFromParcel(parcel);
        map.put(value.getKey(), value.getValue());
    
    return map;

它更冗长但通用。下面是写用法:

writeParcelableMap(map, dest, flags, (mapEntry, parcel, __) -> 
        parcel.write...; //key from mapEntry
        parcel.write...; //value from mapEntry
    );

然后阅读:

map = readParcelableMap(in, parcel ->
    new AbstractMap.SimpleEntry<>(parcel.read... /*key*/, parcel.read... /*value*/)
);

【讨论】:

以上是关于如何将map写入文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 map reduce 的情况下使用 lzo 压缩写入 hadoop hdfs

java自用代码(包括:新建单线程创建文件夹及文件map转为json并将json写入txt文件剪切或改名)

如何在多写入器情况下对文件支持的共享内存中的大页进行故障排除

java如何将一个InputStream写入文件?

C++ 如何将一个文件里的数据写入到另一个文件里?

PHP 中如何在同一个文件中写入而不覆盖以前写的内容