0
0

Java アプリケーション2

Posted at

差分比較が遅い場合、いくつかの方法でパフォーマンスを向上させることができます。特に、以下の方法を試してみることをお勧めします:

1.	インデックスの作成:

テーブルにインデックスを作成することで、検索と比較のパフォーマンスを大幅に向上させることができます。
2. 適切なデータ型の使用:
テーブルのカラムに適切なデータ型を使用することで、パフォーマンスを向上させることができます。
3. 一時テーブルの使用:
一時テーブルを使用して、データの読み込みや比較を効率的に行うことができます。

以下のコード例では、上記の改善を適用しています。

改善したコード例

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.CSVWriter;
import com.opencsv.exceptions.CsvValidationException;

public class CsvToSQLiteApp extends JFrame {
    private static final String DB_URL = "jdbc:sqlite:example.db";
    private JTextField beforeDirPathField;
    private JTextField afterDirPathField;
    private JTextField outputCsvPathField;
    private JCheckBox headerCheckBox;
    private JLabel statusLabel;

    public CsvToSQLiteApp() {
        setTitle("CSV to SQLite App");
        setSize(700, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(5, 5, 5, 5);

        JLabel beforeDirPathLabel = new JLabel("比較元ディレクトリパス:");
        beforeDirPathField = new JTextField(20);
        JButton selectBeforeDirButton = new JButton("Select Before Directory");

        JLabel afterDirPathLabel = new JLabel("比較先ディレクトリパス:");
        afterDirPathField = new JTextField(20);
        JButton selectAfterDirButton = new JButton("Select After Directory");

        JLabel outputCsvPathLabel = new JLabel("Output CSV Path:");
        outputCsvPathField = new JTextField(20);
        JButton diffButton = new JButton("Export Difference to CSV");

        headerCheckBox = new JCheckBox("ヘッダー行あり");
        headerCheckBox.setSelected(true);

        statusLabel = new JLabel();
        statusLabel.setForeground(Color.BLUE);

        gbc.gridx = 0;
        gbc.gridy = 0;
        add(beforeDirPathLabel, gbc);

        gbc.gridx = 1;
        add(beforeDirPathField, gbc);

        gbc.gridx = 2;
        add(selectBeforeDirButton, gbc);

        gbc.gridx = 0;
        gbc.gridy = 1;
        add(afterDirPathLabel, gbc);

        gbc.gridx = 1;
        add(afterDirPathField, gbc);

        gbc.gridx = 2;
        add(selectAfterDirButton, gbc);

        gbc.gridx = 0;
        gbc.gridy = 2;
        add(outputCsvPathLabel, gbc);

        gbc.gridx = 1;
        add(outputCsvPathField, gbc);

        gbc.gridx = 2;
        add(diffButton, gbc);

        gbc.gridx = 0;
        gbc.gridy = 3;
        add(headerCheckBox, gbc);

        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.gridwidth = 3;
        add(statusLabel, gbc);

        selectBeforeDirButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                int result = fileChooser.showOpenDialog(null);
                if (result == JFileChooser.APPROVE_OPTION) {
                    File selectedDir = fileChooser.getSelectedFile();
                    beforeDirPathField.setText(selectedDir.getAbsolutePath());
                }
            }
        });

        selectAfterDirButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                int result = fileChooser.showOpenDialog(null);
                if (result == JFileChooser.APPROVE_OPTION) {
                    File selectedDir = fileChooser.getSelectedFile();
                    afterDirPathField.setText(selectedDir.getAbsolutePath());
                }
            }
        });

        diffButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String beforeDirPath = beforeDirPathField.getText();
                String afterDirPath = afterDirPathField.getText();
                String outputCsvPath = outputCsvPathField.getText();
                boolean hasHeader = headerCheckBox.isSelected();
                try (Connection conn = DriverManager.getConnection(DB_URL)) {
                    importCsvToTable(conn, beforeDirPath, "before", hasHeader);
                    importCsvToTable(conn, afterDirPath, "after", hasHeader);
                    createIndexes(conn, "before");
                    createIndexes(conn, "after");
                    exportDiffToCsv(conn, "before", "after", outputCsvPath);
                    statusLabel.setText("Difference exported to " + outputCsvPath);
                } catch (SQLException ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null, "Error processing CSV files: " + ex.getMessage());
                }
            }
        });
    }

    private void importCsvToTable(Connection conn, String csvDirPath, String tableName, boolean hasHeader) {
        File folder = new File(csvDirPath);
        File[] listOfFiles = folder.listFiles((dir, name) -> name.endsWith(".csv"));

        if (listOfFiles == null) {
            JOptionPane.showMessageDialog(null, "No CSV files found in the directory: " + csvDirPath);
            return;
        }

        try (Statement stmt = conn.createStatement()) {
            stmt.execute("DROP TABLE IF EXISTS " + tableName);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        for (File file : listOfFiles) {
            try (CSVReader csvReader = new CSVReaderBuilder(new InputStreamReader(new FileInputStream(file), "SJIS"))
                    .withSkipLines(0)
                    .build()) {
                String[] headers = hasHeader ? csvReader.readNext() : generateDefaultHeaders(csvReader.peek());
                if (headers == null) {
                    continue;
                }

                while (headers[0].startsWith("#")) {
                    headers = csvReader.readNext();
                    if (headers == null) {
                        break;
                    }
                }

                createTable(conn, tableName, headers);

                String[] row;
                while ((row = csvReader.readNext()) != null) {
                    if (row[0].startsWith("#")) {
                        continue;
                    }
                    insertRow(conn, tableName, headers, row);
                }
            } catch (IOException | CsvValidationException | SQLException e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, "Error processing file " + file.getName() + ": " + e.getMessage());
            }
        }
    }

    private String[] generateDefaultHeaders(String[] sampleRow) {
        String[] headers = new String[sampleRow.length];
        for (int i = 0; i < sampleRow.length; i++) {
            headers[i] = "Column" + (i + 1);
        }
        return headers;
    }

    private void createTable(Connection conn, String tableName, String[] headers) throws SQLException {
        try (Statement stmt = conn.createStatement()) {
            String columns = String.join(" TEXT, ", headers) + " TEXT";
            String createTableSQL = String.format("CREATE TABLE %s (%s)", tableName, columns);
            stmt.execute(createTableSQL);
        }
    }

    private void insertRow(Connection conn, String tableName, String[] headers, String[] row) throws SQLException {
        String columns = String.join(", ", headers);
        String placeholders = String.join(", ", Arrays.asList(row).stream().map(col -> "?").toArray(String[]::new));

        String insertSQL = String.format("INSERT INTO %s (%s) VALUES (%s)", tableName, columns, placeholders);
        try (PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
            for (int i = 0; i < row.length; i++) {
                pstmt.setString(i + 1, row[i]);
            }
            pstmt.executeUpdate();
        }
    }

    private void createIndexes(Connection conn, String tableName) throws SQLException {
        try (Statement stmt = conn.createStatement()) {
            String createIndexSQL = String.format("CREATE INDEX idx_%s ON %s (%s)", tableName, tableName, "column1");
            stmt.execute(createIndexSQL);
        }
    }

    private void exportDiffToCsv(Connection conn, String tableA, String tableB, String outputCsvPath) {
        String sql = String.format("SELECT * FROM %s EXCEPT SELECT * FROM %s", tableA, tableB);

        try (CSVWriter writer = new CSVWriter(new OutputStreamWriter(new FileWriter(outputCsvPath), "SJIS"));
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {

            writer.writeAll(rs, true);
        } catch (SQLException | IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, "Error exporting difference: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new CsvToSQLiteApp().setVisible(true));
    }
}

説明

  1. インデックスの作成

    • createIndexesメソッドを追加し、指定されたテーブルにインデックスを作成します。この例では、column1にインデックスを作成していますが、適切なカラムを指定してください。
  2. テーブルの再作成

    • テーブルのデータを再インポートする際に、既存のテーブルを削除して再作成します。これにより、前回のインポートデータをクリアし、最新のデータのみを使用できます。
  3. PreparedStatementの使用

    • データ挿入の際にPreparedStatementを使用して、パフォーマンスを向上させます。
  4. ヘッダー行の有無の管理

    • ヘッダー行の有無を管理するために、hasHeaderパラメータを使用します。ヘッダーがない場合、generateDefaultHeadersメソッドを使用してデフォルトのヘッダーを生成します。

これにより、データのインポートと比較が効率的になり、パフォーマンスが向上します。適切なカラムにインデックスを作成することで、検索と比較のパフォーマンスが大幅に改善されます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0