【问题标题】:synchronization doesn't working with counter?同步不适用于计数器?
【发布时间】:2015-01-20 16:39:47
【问题描述】:

我编写了一个转换器,它应该从一种文件格式(例如“csv”)转换为另一种文件格式(例如“json”)——对于小文件来说一切正常。 对于较大的文件,我在HashMap<Integer,String> 中使用的int lineCounter 似乎“跳跃”了。 HashMap的第一个条目表示行号,HashMap的第二个条目表示数据。

源 CSV 看起来像这样(大约还有 3600 个条目):

_id,actor.displayName,actor.id,actor.objectType,generator.displayName,generator.id,generator.objectType,generator.url,object.displayName,object.id,object.objectType,provider.displayName,provider.id,provider.inquiryPhase,provider.objectType,provider.url,published,publishedClient,publishedServer,target.displayName,target.id,target.inquiryPhase,target.objectType,verb
,BasKolloeffel(UT),BasKolloeffel(UT)@5485a7050ac61b1339a4da09,person,LochemC,5485a7050ac61b1339a4da09,ils,http://graasp.eu/spaces/5485a7050ac61b1339a4da09,LochemC,5485a7050ac61b1339a4da09,ils,LochemC,5485a7050ac61b1339a4da09,ils,ils,http://graasp.eu/spaces/5485a7050ac61b1339a4da09,2014-12-08T13:40:45.409Z,2014-12-08T13:40:45.409Z,,Orientation,5485a7050ac61b1339a4da0e,Orientation,phase,access

生成的 JSON:

{
    "actor" : {
        "displayName" : "BasKolloeffel(UT)",
        "id" : "BasKolloeffel(UT)@5485a7050ac61b1339a4da09",
        "objectType" : "person"
    },
    "generator" : {
        "displayName" : "LochemC",
        "id" : "5485a7050ac61b1339a4da09",
        "objectType" : "ils",
        "url" : "http://graasp.eu/spaces/5485a7050ac61b1339a4da09"
    },
    "object" : {
        "displayName" : "LochemC",
        "id" : "5485a7050ac61b1339a4da09",
        "objectType" : "ils"
    },
    "provider" : {
        "displayName" : "LochemC",
        "id" : "5485a7050ac61b1339a4da09",
        "inquiryPhase" : "ils",
        "objectType" : "ils",
        "url" : "http://graasp.eu/spaces/5485a7050ac61b1339a4da09"
    },
        "published" : "2014-12-08T13:40:45.409Z",
        "publishedClient" : "2014-12-08T13:40:45.409Z",
    "target" : {
        "displayName" : "Orientation",
        "id" : "5485a7050ac61b1339a4da0e",
        "inquiryPhase" : "Orientation",
        "objectType" : "phase"
    },
    "verb" : "access"
}

在阅读了大约 2000 多条转换后的 csv 行之后,JSON 结构变得混乱并开始看起来像这样:

{
},
"displayName" : "Vogel1",
"actor" : {
    "objectType" : "person"
    "id" : "Vogel1@5485a7050ac61b1339a4da09",
"generator" : {
},
    "id" : "b0e88042-47ec-4bbb-e419-f997020956bc",
    "displayName" : "questioningscratchpad",
    "url" : "http://go-lab.gw.utwente.nl/experiments/2014-12-lochem/questioning_v1/tools/questioning/src/main/webapp/questioning_relative_density.xml"
    "objectType" : "application",
"object" : {
},
    "objectType" : "application"
    "id" : "b0e88042-47ec-4bbb-e419-f997020956bc",
"provider" : {
},
    "id" : "5485a7050ac61b1339a4da09",
    "displayName" : "LochemC",
    "objectType" : "ils",
    "inquiryPhase" : "Conceptualisation",
},
    "url" : "http://graasp.eu/spaces/5485a7050ac61b1339a4da09"
    "publishedClient" : "2014-12-16T10:27:55.097Z",
    "published" : "2014-12-16T10:27:55.097Z",
    "displayName" : "unnamedquestions",
"target" : {
    "objectType" : "questions"
    "id" : "b911e97c-cb7f-4cec-ab99-440aecb029f5",
    "verb" : "access"
}

我已经调试了 HashMap 的 lineCounter(上 50%,因为在一切正常之前),并且在使用 System.out.println(this.lineCounter); 时得到以下结果:

65557
65591
65623
65657
65691
65725
65759
65790
65821

我希望 lineCounter 对于 csv 文件中的每个标记只会增加 1 (+1),而不是 30 或类似的东西。我认为这是一个同步问题,但即使是同步块也不能解决这个问题。

我正在使用这2种方法来修改HashMap:

public synchronized void putLineToMap(int lineCounter, String content) {
    this.lineMap.put(lineCounter, content);
    ++this.lineCounter;
}

public synchronized String replaceToken(String previousLine, String token, String replace) {
    --this.lineCounter;
    previousLine = this.readerSaver.replaceLast(previousLine, token, replace);
    return previousLine;
}

...为了完整起见,我将添加 replaceLast 方法:

/*
 * @param   string      The String-Object to be changed.
 * @param   substring   The String-Object-Part to be replaced.
 * @param   replacement The String-Object which should replace the substring.
 * @return                  The (changed) String-Object.
 */
public String replaceLast(String string, String substring, String replacement) {
    int index = string.lastIndexOf(substring);
    if (index == -1) {
        return string;
    }
    return string.substring(0, index) + replacement
            + string.substring(index + substring.length());
}

谁能帮帮我?

** 编辑 ** 这是我用来将 CSV 转换为 JSON 的方法。

/**
 * A utility function which gathers the data from a csv file to store it in
 * a for this fitting architecture. Afterwards the data will be processed
 * and stored in a valid JSON format.
 *
 * @param headerLineData The header of the CSV.
 * @param rowLineData ALL rows of the CSV with separator symbols between the
 * lines.
 * @param filepath The filepath where the JSON file should be saved to.
 * @param entries If a config file is used, one can find the header data to
 * parse in this hashset. If entries is null, the config file won't be used.
 */
public void createJSON(String headerLineData, String rowLineData, String filepath, TreeSet<String> entries) {

    try {
        String[] headerSeparatedData = headerLineData.split(",");

        //??? @flagLastValueLine
        boolean flagLastValueLine = false;
        //count the number of value rows.
        this.scan = new Scanner(rowLineData);
        while (this.scan.hasNext()) {
            this.scan.nextLine();
            ++this.numberLines;
        }

        //resetting the scanner
        this.scan = new Scanner(rowLineData);

        while (this.scan.hasNext()) {
            //Read first value row.
            String nextLine = this.scan.nextLine();
            //Split value-row.
            String[] rowData = nextLine.split(",");

            //For the first iteration - start tag
            if (this.whileLoopPassCounter == 0) {
                putLineToMap(this.lineCounter, "[");
            }

            //Debug
            if (this.lineCounter >= 65536) {
                System.out.println(this.lineCounter);
            }

            //Depth of current header node -> actor.id.ID -- Depth = 2
            int depthHeaderLevel = 0;

            //should keep in mind which key (without value-node) was last.
            Set<String> rememberKeyNode = new TreeSet<String>();

            //Iterate through all elements of the header row. If 4x "," = 5 Elements.
            for (int i = 0; i < headerSeparatedData.length; i++) {
                if (i == 0) {
                    putLineToMap(this.lineCounter, "{");
                }

                //proof whether the config file is used. Only parse the header data in this hashset.
                if (entries != null) {
                    Iterator<String> it = entries.iterator();
                    int size = entries.size();
                    int newSize = 0;
                    while (it.hasNext()) {
                        String key = it.next();
                        if (!headerSeparatedData[i].contains(key)) {
                            ++newSize;
                        }
                    }
                    if (newSize == size) {
                        continue;
                    }

                }

                //is rowData empty? Then jump to the next condition.
                if (!rowData[i].equals("")) {
                    //get all single elements of the header and split them again. case: have sub-elements.
                    if (headerSeparatedData[i].contains(".")) {
                        String[] headerSeparatedLevelData = headerSeparatedData[i].split("\\.");
                        depthHeaderLevel = headerSeparatedLevelData.length;
                        //Iterate through the depth of Header Level
                        for (int k = 0; k < depthHeaderLevel; k++) {
                            //First case: headerlevel does NOT contain any direct value successor.
                            if (k <= depthHeaderLevel - 2 && !rememberKeyNode.contains(headerSeparatedLevelData[k])) {
                                //special case: does the last row contain a "," from the deepest level?
                                //if yes: set close-tag and begin a new block after this one.
                                int lines = 0;
                                synchronized (getClass()) {
                                    lines = this.lineCounter - 1;
                                }

                                String previousLine = this.lineMap.get(lines);
                                if (previousLine.contains(",") && this.flagSingleNode == false) {
                                    //decrement counter to edit the last line.
                                    previousLine = replaceToken(previousLine, ",", "");

                                    //edit last line and increment counter.
                                    putLineToMap(this.lineCounter, previousLine);
                                    //set close tag.
                                    putLineToMap(this.lineCounter, "},");
                                    //if one goes in an other level than the first: remove flag / set false.
                                    flagLastValueLine = false;
                                    /**
                                     * GEPFUSCHT!
                                     */
                                    //case: last row contains "},"
                                    int lines2 = 0;
                                    synchronized (getClass()) {
                                        lines2 = this.lineCounter - 1;
                                    }
                                    String prevLine = this.lineMap.get(lines2);
                                    if (prevLine.contains("},") && k == 0) {
                                        //decrement counter to remove the last line.
                                        prevLine = replaceToken(prevLine, "},", "}");

                                        synchronized (getClass()) {
                                            this.lineMap.remove(this.lineCounter);
                                        }

                                        //notice the depth of the header level.
                                        for (int j = 0; j < depthHeaderLevel - 1; j++) {
                                            //if end node not reached, just put "}"
                                            if (j < depthHeaderLevel - 2) {
                                                putLineToMap(this.lineCounter, "}");

                                            } //if end nose is reached, set close tag.
                                            else {
                                                putLineToMap(this.lineCounter, "},");

                                            }
                                        }
                                    }
                                }
                                rememberKeyNode.add(headerSeparatedLevelData[k]);
                                putLineToMap(this.lineCounter, "\"" + headerSeparatedLevelData[k] + "\" : {");

                                this.flagSingleNode = false;
                            } //second case: headerlevel has a text node as his successor.
                            else if (!rememberKeyNode.contains(headerSeparatedLevelData[k])) {
                                putLineToMap(this.lineCounter, "\"" + headerSeparatedLevelData[k] + "\" : " + "\"" + rowData[i] + "\",");

                                //if one is in the last level, flag should be set.
                                flagLastValueLine = true;
                            }
                        }
                    } //Header does not contain "." - Separation not necessary.
                    else {
                        //set the depthHeaderLevel to one, because there is only one element at the header.
                        depthHeaderLevel = 1;
                        if (!rememberKeyNode.contains(headerSeparatedData[i])) {
                            //if last line ends on ",", replace through "},"
                            int line = 0;
                            synchronized (getClass()) {
                                line = this.lineCounter - 1;
                            }
                            String prevLine = this.lineMap.get(line);
                            if (prevLine.contains(",") && !this.flagSingleNode) {
                                //decrement counter
                                prevLine = replaceToken(prevLine, ",", "");
                                putLineToMap(this.lineCounter, prevLine);
                                putLineToMap(this.lineCounter, "},");
                            }
                            putLineToMap(this.lineCounter, "\"" + headerSeparatedData[i] + "\" : " + "\"" + rowData[i] + "\",");
                            //if one is in the last level, flag should be set.
                            flagLastValueLine = true;
                            rememberKeyNode.add(headerSeparatedData[i]);
                            this.flagSingleNode = true;
                        }
                    }
                }
                //Three things done here:
                //1. if the last line contains a "," - remove it.
                //2. dynamically add the close tags of a BLOCK
                //3. reset the TreeSet
                if (i == headerSeparatedData.length - 1) {
                    int line = 0;
                    synchronized (getClass()) {
                        line = this.lineCounter - 1;
                    }
                    String prevLine = this.lineMap.get(line);
                    if (prevLine.contains(",")) {
                        //decrement counter to edit the last line with ",".
                        prevLine = replaceToken(prevLine, ",", "");
                        putLineToMap(this.lineCounter, prevLine);
                    }
                    //dynamically add the close tags of a BLOCK.
                    for (int l = 0; l < depthHeaderLevel; l++) {
                        if (l == depthHeaderLevel - 1) {
                            putLineToMap(this.lineCounter, "},");
                        } else {
                            putLineToMap(this.lineCounter, "}");
                        }

                    }
                    rememberKeyNode = new TreeSet<String>();
                }
            }
            this.whileLoopPassCounter++;

            if (this.whileLoopPassCounter == this.numberLines) {
                //remove last "," - if there is one.
                String prevLine = this.lineMap.get(this.lineCounter - 1);
                if (prevLine.contains(",")) {
                    //decrement counter to edit the last line.
                    prevLine = replaceToken(prevLine, ",", "");
                    putLineToMap(this.lineCounter, prevLine);
                }

                //close tag
                putLineToMap(this.lineCounter, "]");
            }
        }
        this.scan.close();
        saveResultToFile(this.lineMap, filepath);
    } catch (IOException ex) {
        Logger.getLogger(CSVtoJSONStructureHelper.class.getName()).log(Level.SEVERE, null, ex);
    }
}

【问题讨论】:

  • 这里缺少太多东西。你在哪里打印行号?什么是replaceToken(输入)?你如何使用它? readerSaver 是什么?你是如何生成 JSON 的?
  • 好吧,我认为整个方法太多了。我将在几秒钟后在这里发布第一部分。
  • 希望够了@SotiriosDelimanolis。
  • 可以在这里回答您的问题:我在名为 savedResultToFile 的方法中打印 lineNumber。它的输入是 HashMap 和文件名。 BufferedWriter 将 HashMap 的内容逐行写入我创建的文件中。对于replaceToken 的输入,请参见readerSaver 的方法replaceLastreaderSaver 只是一个实用类,里面有这个方法。
  • 为什么要在代码中放入随机同步的东西?您正在混合实例一个类锁......除了没有涉及的线程(显然):S

标签: java json csv synchronization


【解决方案1】:

您提到使用HashMap 来保存行号+ json 条目的Map&lt;Integer, String&gt;,但HashMap 不维护条目迭代的插入顺序。

如果需要保证迭代顺序与插入顺序相同,可以使用LinkedHashMap

【讨论】:

  • 假设 HashMap 维护顺序真是大错特错。谢谢!
  • @X-Fate,没问题,您应该注意java.util.Map 接口没有顺序保证,但具体实现可以(LinkedHashMap 的类级 Javadocs 对此进行了概述)跨度>
【解决方案2】:

我来猜一猜。

如果您的程序使用前几个数据点,那么我猜您的其余数据并不那么干净。也许某些行缺少 csv 文件中某些列的值。我建议您检查从输入文件中读取的每一行。

a. read one line from file
b. check if the line is in the expected format
     b.1 tokenized the line
     b.2 check if the number of tokens (length) is equal to the expected value, if not discard the line or do some thing to salvage the incomplete data point. 

【讨论】:

  • 嘿,谢谢你的提议,但我已经证明了文件。几乎每一行看起来都像我发布的行。当然在某些情况下缺少令牌,但我已经编写了一个处理这种情况的方法。也不可能前 2000 行能正确读取,而后 1600 行不能。
  • 如果我是你,我将创建一个版本,该版本忽略具有缺失值的数据点作为比较点。然后我将从那里开始调试。
猜你喜欢
  • 1970-01-01
  • 2018-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-28
  • 1970-01-01
相关资源
最近更新 更多