仅当匹配阈值字节

时间:2018-02-01 06:41:51

标签: java algorithm data-structures utf-8 stringbuilder

我有一个tasks列表对象,我正在迭代并将每个任务对象附加到StringBuilder后跟新行,如下所示。现在我将继续在同一个字符串生成器中追加任务对象,直到它达到60000字节的大小限制。一旦达到限制,我将填充此字符串作为映射中的值,键将是带增量索引的文件名。然后我将重置字符串构建器和其他东西并再次重复此过程。

因此,如果我有一个大的tasks对象,那么我将拆分成多个字符串对象,其大小应始终小于60000字节。

我得到了下面的代码,但我总是看到地图中的值大小超过60000字节。我做错了什么?此外,我在两个不同的地方填充HashMap - 一个达到限制,另一个是达不到限制。

  public void populate(final List<Task> tasks) {
    Map<String, String> holder = new HashMap<>();
    int size = 0;
    int index = 0;
    StringBuilder sb = new StringBuilder();
    for (Task task : tasks) {
      sb.append(task).append(System.getProperty("line.separator"));
      size = sb.toString().getBytes(StandardCharsets.UTF_8).length;
      if (size > 60000) {
        String fileName = "tasks_info_" + index + ".txt";
        holder.put(fileName, sb.toString());
        index++;
        sb = new StringBuilder();
        size = 0;
      }
    }
    // for cases where we don't reach the limit
    if(sb.toString().length > 0) {
        String fileName = "tasks_info_" + index + ".txt";
        holder.put(fileName, sb.toString());        
    }
    System.out.println(holder);
  }

注意:如果每个Task对象都超过60000 bytes,那么我将立即删除该对象并转到下一个条目。但实际上,它不会发生。

更新

public void populate(final List<Task> tasks, final long timestamp) {
    Map<String, String> holder = new HashMap<>();
    int size = 0;
    int index = 0;
    int nl = System.getProperty("line.separator").getBytes(StandardCharsets.UTF_8).length;
    StringBuilder sb = new StringBuilder();
    // new change
    sb.append(timestamp).append(System.getProperty("line.separator"));
    for (Task task : tasks) {
        int ts = String.valueOf(task).getBytes(StandardCharsets.UTF_8).length;
        if (size + ts + nl > 60000) {
            String fileName = "tasks_info_" + index + ".txt";
            holder.put(fileName, sb.toString());
            index++;
            sb = new StringBuilder();
            // new change
            sb.append(timestamp).append(System.getProperty("line.separator"));          
            size = 0;
        }
        sb.append(task).append(System.getProperty("line.separator"));
        size += ts + nl;
    }
    // for cases where we don't reach the limit
    if (size > 0) { // size can only be 0 if you have 0 tasks
        String fileName = "tasks_info_" + index + ".txt";
        holder.put(fileName, sb.toString());        
    }
    System.out.println(holder);
}

3 个答案:

答案 0 :(得分:3)

其他答案已经提到了它不起作用的原因(在它已经超出限制之后添加)。但我认为到目前为止没有一个实现是正确的,不仅因为新行的大小被省略了。

public Map<String, String> populate(final List<Task> tasks) {
    Map<String, String> holder = new HashMap<>();
    if (tasks.size() == 0)
        return holder;
    int index = 0;
    int nl = System.getProperty("line.separator").getBytes(StandardCharsets.UTF_8).length;
    StringBuilder sb = new StringBuilder();
    sb.append(System.currentTimeMillis()).append(System.getProperty("line.separator"));
    int size = sb.toString().getBytes(StandardCharsets.UTF_8).length;
    for (Task task : tasks) {
        int ts = String.valueOf(task).getBytes(StandardCharsets.UTF_8).length;
        if (size + ts + nl > 60000) {
            String fileName = "tasks_info_" + index + ".txt";
            holder.put(fileName, sb.toString());
            index++;
            sb = new StringBuilder();
            sb.append(System.currentTimeMillis()).append(System.getProperty("line.separator"));
            size = sb.toString().getBytes(StandardCharsets.UTF_8).length;
        }
        sb.append(task).append(System.getProperty("line.separator"));
        size += ts + nl;
    }
    String fileName = "tasks_info_" + index + ".txt";
    holder.put(fileName, sb.toString());        
    return holder;
}

答案 1 :(得分:1)

我尝试了您的代码以确保解决方案。在将新任务的值实际添加到SB之前,您需要尝试检查下一个大小。我修改了代码以反映这个解决方案。你可以尝试一下,告诉我们它是否适合你?

public  void populate(final List<Task> tasks) {
        Map<String, String> holder = new HashMap<>();
        int size = 0;
        int index = 0;
        int lengthTask = 0;
        int lengthSb = 0;
        StringBuilder sb = new StringBuilder();
        for (Task task : tasks) {
            lengthTask = task.toString().getBytes(StandardCharsets.UTF_8).length;
            lengthSb = sb.toString().getBytes(StandardCharsets.UTF_8).length;
            if (size + lengthTask + lengthSb > 60000) {
                System.out.println("last added size "+size);
                String fileName = "tasks_info_" + index + ".txt";
                holder.put(fileName, sb.toString());
                index++;
                sb = new StringBuilder();
                size = 0;
            }
            sb.append(task).append(System.getProperty("line.separator"));
            size += sb.toString().getBytes(StandardCharsets.UTF_8).length;
            System.out.println("size "+size);

        }
        // for cases where we don't reach the limit
        String fileName = "tasks_info_" + index + ".txt";
        holder.put(fileName, sb.toString());
        System.out.println(holder);
    }

答案 2 :(得分:0)

如果我正确理解了代码,我想它应该是

 size = sb.toString().getBytes(StandardCharsets.UTF_8).length;

目前它在字符串大小超过60000字节后插入映射,因此映射中的值超过60000字节

if (size > 60000) {
    ...
    holder.put(fileName, sb.toString());
    ...
}