Чтение огромного CSV-файла и преобразование в JSON с Java 8 - PullRequest
0 голосов
/ 20 сентября 2018

Я пытаюсь прочитать CSV-файл со многими столбцами.И первая строка всегда является заголовком файла CSV.Я хотел бы преобразовать данные CSV в JSON.Я могу прочитать его как String и преобразовать в JSON, но я не могу назначить ему заголовки.

Например, ввод csv выглядит следующим образом:

first_name,last_name
A,A1
B,B1
C,C1

Stream<String> stream = Files.lines(Paths.get("sample.csv"))
List<String[]> readall = stream.map(l -> l.split(",")).collect(Collectors.toList()); 

или

List<String> test1 = readall.stream().skip(0).map(row -> row[1]).collect(Collectors.toList());

И использование com.fasterxml.jackson.databind.ObjectMapper's WriteValueAsString создает только JSON без заголовка,

Я бы хотел вывод в формате, подобном

{
[{"first_name":"A","last_name":"A1"},{"first_name":"B"....

Как использовать поток в Java для подготовки этого формата JSON?

Пожалуйста, помогите.

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

Я думаю, это то, что вы пытаетесь сделать

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class App {
    public static void main(String[] args) throws JsonProcessingException, IOException {

        Stream<String> stream = Files.lines(Paths.get("src/main/resources/test1.csv"));
        List<Map<String, Object>> readall = stream.map(l -> {
            Map<String, Object> map = new HashMap<String, Object>();
            String[] values = l.split(",");

            map.put("name", values[0]);
            map.put("age", values[1]);

            return map;
        }).collect(Collectors.toList());

        ObjectMapper mapperObj = new ObjectMapper();
        String jsonResp = mapperObj.writeValueAsString(readall);
        System.out.println(jsonResp);

    }
}

Работает с потоками Java -8, с заголовками и использует Джексон для преобразования его в json.б / у CSV

abc,20
bbc,30
0 голосов
/ 20 сентября 2018

Я бы решил эту проблему в два этапа: сначала прочитал заголовки, затем прочитал остальные строки:

static String[] headers(String path) throws IOException {

    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine().split(",");
    }
}

Теперь вы можете использовать описанный выше метод следующим образом:

String path = "sample.csv";

// Read headers
String[] headers = headers(path);

List<Map<String, String>> result = null;

// Read data
try (Stream<String> stream = Files.lines(Paths.get(path))) {
    result = stream
        .skip(1) // skip headers
        .map(line -> line.split(","))
        .map(data -> {
            Map<String, String> map = new HashMap<>();
            for (int i = 0; i < data.length; i++) {
               map.put(headers[i], data[i]);
            }
            return map;
        })
        .collect(Collectors.toList());
}

Вы можете изменить цикл for внутри 2-й операции map:

try (Stream<String> stream = Files.lines(Paths.get(path))) {
    result = stream
        .skip(1) // skip headers
        .map(line -> line.split(","))
        .map(data -> IntStream.range(0, data.length)
            .boxed()
            .collect(Collectors.toMap(i -> headers[i], i -> data[i])))
        .collect(Collectors.toList());
}

РЕДАКТИРОВАТЬ: Если вместо сбора в список вы хотитечтобы выполнить действие для карт, считываемых из каждой строки, вы можете сделать это следующим образом:

try (Stream<String> stream = Files.lines(Paths.get(path))) {
    stream
        .skip(1) // skip headers
        .map(line -> line.split(","))
        .map(data -> IntStream.range(0, data.length)
            .boxed()
            .collect(Collectors.toMap(i -> headers[i], i -> data[i])))
        .forEach(System.out::println);
}

(здесь действие состоит в печати каждой карты).

Эта версия может быть улучшенато есть он упаковывает поток int с, а затем снова распаковывает каждый int, чтобы использовать его в качестве индекса массивов headers и data.Кроме того, удобочитаемость может быть улучшена путем извлечения создания каждой карты в частный метод.

Примечания: Возможно, чтение файла дважды - не лучший подход с точки зрения производительности, но код прост и выразителен.Помимо этого, null обработка, преобразование данных (т. Е. В числа или даты и т. Д.) И граничные случаи (т. Е. Без заголовков, без строк данных или различной длины для массивов данных и т. Д.) Остаются в качестве упражнения для читателя.;)

0 голосов
/ 20 сентября 2018

Очень просто, не конвертируйте его в список строк.Преобразуйте его в список HashMaps, а затем используйте библиотеку org.json, чтобы преобразовать его в json.Используйте Джексон для преобразования CSV в Hashmap

Пусть входной поток будет

InputStream stream = new FileInputStream(new File("filename.csv"));

Пример: Чтобы преобразовать CSV в HashMap

public List<Map<String, Object>> read(InputStream stream) throws JsonProcessingException, IOException {
 List<Map<String, Object>> response = new LinkedList<Map<String, Object>>();
 CsvMapper mapper = new CsvMapper();
 CsvSchema schema = CsvSchema.emptySchema().withHeader();
 MappingIterator<Map<String, String>> iterator = mapper.reader(Map.class).with(schema).readValues(stream);
 while (iterator.hasNext()) 
 {
       response.add(Collections.<String, Object>unmodifiableMap(iterator.next()));
 }
 return response;
 }

Чтобы преобразовать Список карты вJson

JSONArray jsonArray = new JSONArray(response);
System.out.println(jsonArray.toString());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...