質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

1730閲覧

CSVファイルを固定長のテキストファイルに出力したい

moo1211

総合スコア3

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2023/04/20 05:01

編集2023/04/20 05:57

前提・ 実現したいこと

【実現したいこと一覧】
①ダブルコーテーションがあったら、削除してテキストファイルに書き込みたい(すでに実装済み?)
②数値項目は値の前に、0埋めをしたい(すでに実装済み)
③半角文字項目は値の後ろに、半角スペース埋めをしたい
④全角文字項目は値の後ろに、全角スペース埋めをしたい

【変換前CSVファイル】 B,2023,1,22,1,1234567,12345,"山田たろう           " B,2023,1,22,1,123456,1234,"佐藤けん    "

上記のようなCSVファイルをJavaで読み込み、テキストファイルに変換するプログラムを作っています。

【変換後テキストファイル】 B2023012211234567000012345山田たろう            B2023012210123456000001234佐藤けん            

↓こちらの質問を参考にソースを作成しております。
https://teratail.com/questions/329018
それぞれ(1バイト,4バイト,2バイト,2バイト,1バイト,7バイト,9バイト,32バイト(全角16文字))の固定長で変換したいと思っています。

データ例(数値項目):
変換前:1
変換後:01(2バイト)

データ例(半角文字項目):
変換前:"B"
変換後:B(1バイト)

データ例(半角文字項目):
変換前:"G"
変換後:G␣(2バイト)
※半角スペースは␣で表現しています

データ例(全角文字項目):
変換前:"佐藤けん□□□□"
変換後:佐藤けん□□□□□□□□□□□□(32バイト)
※全角スペースは□で表現しています。また、半角全角混合のパターンは無いと想定しています。

発生している問題・エラーメッセージ

名前(山田たろう)がnumberで認識されちゃってるのでエラー(34行目)が発生している?みたいなことは何となくわかるのですが、具体的に何が問題なのかがわかりません。
また、「%04d」は0を4つdecimalで出力みたいな感じの意味を調べて理解できたのですが、「%-100s」の意味や28行目全体のそもそもの意味が調べてもよくわかっておらず、エラーが解消できていないと思っています。

【エラーメッセージ】 java.lang.NumberFormatException: For input string: "山田たろう           " at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Integer.parseInt(Integer.java:665) at java.base/java.lang.Integer.parseInt(Integer.java:781) at CsvToText5.main(CsvToText5.java:34) 異常終了しました。

該当のソースコード

Java

1//package jp.aast.kyoiku; 2import java.io.BufferedReader; 3import java.io.BufferedWriter; 4import java.io.FileInputStream; 5import java.io.FileOutputStream; 6import java.io.InputStreamReader; 7import java.io.OutputStreamWriter; 8 9 10public class CsvToText5 { 11 12 public static void main(final String args[]) { 13 try ( 14 BufferedReader reader = new BufferedReader(new InputStreamReader( 15 new FileInputStream(args[0]), "Windows-31J")); 16 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( 17 new FileOutputStream(args[1]), "Windows-31J"))) { 18 19 while (reader.ready()) { 20 //入力ファイルから1行読み込む。 21 final String line = reader.readLine(); 22 final FileOutputStream os = new FileOutputStream(args[1]); 23 24 final String enc = "Windows-31J"; 25 26 final String[] items = line.replace("\"", "").split(","); 27 //行データを出力ファイルへ書き出す。 28 os.write(String.format("%-100s", items[0]).getBytes(enc), 0, 1); 29 os.write(String.format("%04d", Integer.parseInt(items[1])).getBytes(enc)); 30 os.write(String.format("%02d", Integer.parseInt(items[2])).getBytes(enc)); 31 os.write(String.format("%02d", Integer.parseInt(items[3])).getBytes(enc)); 32 os.write(String.format("%01d", Integer.parseInt(items[4])).getBytes(enc)); 33 os.write(String.format("%07d", Integer.parseInt(items[5])).getBytes(enc)); 34 os.write(String.format("%09d", Integer.parseInt(items[6])).getBytes(enc)); 35 os.write(String.format("%-100s", items[7]).getBytes(enc), 0, 32); 36 37 os.close(); 38 39 } 40 41 } catch (Exception e) { 42 e.printStackTrace(); 43 44 System.out.println("異常終了しました。"); 45 System.exit(-1); 46 } 47 48 System.out.println("正常終了しました。"); 49 System.exit(0); 50 51 } 52 53} 54 55

考えをまとめ切れておらず、わかりづらい質問となってしまい申し訳ありませんが、問題の一部分についてのみでもいいのでご回答いただけると幸いです。

お忙しいところ恐縮ですがよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moo1211

2023/04/20 05:24

閲覧いただきありがとうございます! raikuan様からご指摘をいただき、itemのインデックスを0からに修正したところ正常終了まではできたので質問文中のソースも修正させていただきます!
jimbe

2023/04/20 05:28

出力ファイルを 16 行目で writer として生成しているのに 22 行目で新しく生成してたりしては思い通りには動作しないでしょう。 ファイルの扱い・配列の扱い・フォーマットの扱いとあちこちに学習に抜けがあるようです。
moo1211

2023/04/20 05:30

ご回答ありがとうございます! 学習に抜けがあるのはおっしゃる通りです、、 22行目付近をもう一度見直してみます!
jimbe

2023/04/20 05:34 編集

まずcsvファイルを一行ずつコピーするプログラムにしてから、変換を実装しては如何でしょうか。 そうすれば変換が悪いのかファイルの扱いが悪いのかが分かるはずです。
jimbe

2023/04/20 05:51

変換前の CSV に項目が一つ足りないようです。
moo1211

2023/04/20 05:56

jimbe様 色々とアドバイスいただきありがとうございます! おっしゃる通りで足りていなかったので質問文中もすぐに修正させていただきます!
shiketa

2023/04/21 00:29

> の固定長で変換したいと思っています。 わたしの少ない経験から助言させていただくと、固定長のデータを扱う時は、java.nio.ByteBuffer が非常に便利です。 * https://docs.oracle.com/javase/jp/8/docs/api/java/nio/ByteBuffer.html java.nioだとChannelを使わないといけないようにおもうかもしれませんが、`os.write(bb.array())`でOutputStreamに吐き出せます。参考まで。
moo1211

2023/04/21 01:28

shiketa様 アドバイスいただきありがとうございます! 過去の類似質問の回答も非常に参考にさせていただいております! 私がjava bronze程度の初歩の初歩の知識しかもっておらず、すべてを理解しきれていないのですが、ちゃんと既存パッケージの勉強もしなきゃ使える知識にならないなと痛感しております、、 java.nio.ByteBufferについてもこの後調べたりしてみます! またご指摘やアドレス等ありましたらいただけますと幸いです。
guest

回答2

0

ベストアンサー

出力ファイルをループ毎に作り直す必要は全くありません。
また、 String.format を利用するのなら、PrintWriter ( の printf) を利用するテもあります。

パラメータを指定してファイルの入出力をするプログラムはテストするのに色々面倒ですので、プログラムを工夫してただ実行すればテスト出来るようにすると楽です。

※クラス名を変更してあります

java

1//package teratail_java.q_eopncfeocqwy3h; 2 3import java.io.*; 4 5public class CsvToText5a { 6 private final static String CHARSET_NAME = "Windows-31J"; 7 8 public static void main(String args[]) { 9 try(BufferedReader reader = getReader(args.length >= 1 ? args[0] : null); 10 PrintWriter writer = getWriter(args.length >= 2 ? args[1] : null)) { 11 for(String line; (line = reader.readLine()) != null; ) { 12 final String[] items = line.split(",", 8); 13 writer.printf("%1s%04d%02d%02d%01d%07d%09d%.16s|\n", //テスト時は最期が分かり易いように改行の直前に '|' 等の目印を入れると良い 14 items[0], 15 Integer.parseInt(items[1]), 16 Integer.parseInt(items[2]), 17 Integer.parseInt(items[3]), 18 Integer.parseInt(items[4]), 19 Integer.parseInt(items[5]), 20 Integer.parseInt(items[6]), 21 (items[7].replaceAll("\"","")+" ".repeat(16))); 22 } 23 System.out.println("正常終了しました。"); 24 System.exit(0); 25 } catch(Throwable t) { 26 t.printStackTrace(); 27 System.out.println("異常終了しました。"); 28 System.exit(-1); 29 } 30 } 31 //テスト時にわざわざパラメータを指定したりファイルを用意したり確認したりが面倒なので、パラメータ無しでただ実行すればテスト出来るようにする 32 private static BufferedReader getReader(String filename) throws IOException { 33 if(filename != null) return new BufferedReader(new InputStreamReader(new FileInputStream(filename), CHARSET_NAME)); 34 //テスト用 35 return new BufferedReader(new StringReader( 36 "B,2023,1,22,1,1234567,12345,\"山田たろう           \"\n" + 37 "B,2023,1,22,1,123456,1234,\"佐藤けん    \"" 38 )); 39 } 40 private static PrintWriter getWriter(String filename) throws IOException { 41 if(filename != null) return new PrintWriter(new OutputStreamWriter(new FileOutputStream(filename), CHARSET_NAME), true); 42 //テスト用 43 return new PrintWriter(System.out, true); 44 } 45}

実行結果

plain

1B2023012211234567000012345山田たろう           | 2B2023012210123456000001234佐藤けん            | 3正常終了しました。

投稿2023/04/20 06:24

編集2023/04/26 03:34
jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moo1211

2023/04/20 06:54

ご回答いただきありがとうございます! すみません、javaというかプログラム自体に疎く、読んで咀嚼して理解するのに膨大な時間がかかるので色々調べて実行してみた後に改めて返信させていただきます。 大変勉強になります、ありがとうございます!
jimbe

2023/04/20 07:45

あっちのアレとそっちのソレとこっちのコレをただ並べれば出来る…ようにはプログラミングは出来ませんので、一つずつ分かっていく為に時間が掛かるのは全く問題ありません。
moo1211

2023/04/26 02:17

jimbe様 お世話になっております。 ご返信が遅くなり申し訳ございません。 ご回答いただいたソースをじっこうしてみたのですが、コンソール上で表示されてしまい、ファイルの読み込み・書き込みがどうしてもできません。 filenameを定義したところ、「CsvToText3a.java:59: エラー: 変数 filenameはすでにメソッド getReader(String)で定義されています」のようなエラーが発生したため、filename1,filename2のようにしたのですが、こちらも「CsvToText3a.java:71: エラー: staticでない変数 filename2をstaticコンテキストから参照することはできません」のようなエラーが発生しうまくいきませんでした。 実行ができないという初歩的なご質問で大変恐縮なのですが、考え方が間違っている部分がある気がするので、もし可能でしたら個指摘いただけませんでしょうか。 現時点での理解をコメントで記載しております。 ```java //package teratail_java.q_eopncfeocqwy3h; import java.io.*; public class CsvToText3a { private final static String CHARSET_NAME = "Windows-31J"; public static void main(String args[]) { //try-catch文。tryの後ろが例外じゃない場合の処理、catchの後ろが例外の場合の処理。 //BufferedReaderクラスのメソッド(調べてもよくわからず)getReader実行処理。 //引数の長さが1以上かどうかを判定→True(1以上)の場合:args[0]を返す、False(1未満)の場合:nullを返す。 try(BufferedReader reader = getReader(args.length >= 1 ? args[0] : null); //文字列出力用のストリームを出力するためにPrintWriterオブジェクトを取得する。(Webページより) //PrintWriterクラスのメソッドgetWriter実行処理。 //引数の長さが2以上かどうかを判定→True(2以上)の場合:args[1]を返す、False(2未満)の場合:nullを返す。 PrintWriter writer = getWriter(args.length >= 2 ? args[1] : null)) { //for文でcsvを1行ずつ読み込み、最後の行まで繰り返す for(String line; (line = reader.readLine()) != null; ) { //String型の配列 itemsを定義する //csvの1行をカンマ区切りで8個の要素に分割する final String[] items = line.split(",", 8); //PrintWriterクラスのprintfメソッドを実行。 //printfの後ろは書式指定 //半角スペース1つ、0を4つ、0を2つ、0を2つ、0を1つ、0を7つ、0を9つ、全角スペースを16個までそれぞれ出力する書式設定で出力する。 writer.printf("%1s%04d%02d%02d%01d%07d%09d%.16s|\n", //テスト時は最期が分かり易いように改行の直前に '|' 等の目印を入れると良い //CSVの1列目 items[0], //CSVの2列目をInt型に変換、以下items[6]まで同様 Integer.parseInt(items[1]), Integer.parseInt(items[2]), Integer.parseInt(items[3]), Integer.parseInt(items[4]), Integer.parseInt(items[5]), Integer.parseInt(items[6]), //CSV8列目のダブルコーテーションを全部nullに置換。後ろに全角スペース16個出力。 (items[7].replaceAll("\"","")+" ".repeat(16))); } System.out.println("正常終了しました。"); System.exit(0); } catch(Throwable t) { t.printStackTrace(); System.out.println("異常終了しました。"); System.exit(-1); } } //テスト時にわざわざパラメータを指定したりファイルを用意したり確認したりが面倒なので、パラメータ無しでただ実行すればテスト出来るようにする //getReaderメソッドの実行。String型のfilenameがnullだったらIOExceptionで例外処理をする。 private static BufferedReader getReader(String filename) throws IOException { //filenameがnullではなかった場合(ファイルが読み込めた場合)、読み込んだファイルを入力として戻り値にする。 File filename = new File("C:\\INPUT.CSV"); if(filename != null) return new BufferedReader(new InputStreamReader(new FileInputStream(filename), CHARSET_NAME)); //テスト用 //ファイルが読み込めなかった場合は64,65行目を入力にして戻り値として返す。 return new BufferedReader(new StringReader( "B,2023,1,22,1,1234567,12345,\"山田たろう           \"\n" + "B,2023,1,22,1,123456,1234,\"佐藤けん    \"" )); } File filename2 = new File("C:\\OUTPUT"); //getReaderメソッドの実行。String型のfilenameがnullだったらIOExceptionで例外処理をする。 private static PrintWriter getWriter(String filename2) throws IOException { //filenameがnullではなかった場合、そのファイルに出力をする。 if(filename2 != null) return new PrintWriter(new OutputStreamWriter(new FileOutputStream(filename2), CHARSET_NAME)); //テスト用 //filenameがnullだったらコンソールに出力する。 return new PrintWriter(System.out, true); } } ``` お忙しいところ恐縮ですがよろしくお願いいたします。
jimbe

2023/04/26 08:45 編集

まず、回答のコードは質問に提示されたコードと同じパラメータを指定して実行すれば同じ動作(ファイル入出力)するようにした上で、パラメータ無しで実行すれば画面に表示して確認を簡単にするようにしています。 ですので、filename/filename2 等の追加修正をするのではなく、実行時にパラメータとして指定してください。 質問のコードを CsvToText5 C:\INPUT.CSV C:\OUTPUT として実行していたのなら CsvToText5a C:\INPUT.CSV C:\OUTPUT として実行してください。 getReader/getWriter は BufferedReader/PrintWriter のメソッドではありません。CsvToText5a 内の後の方(32/40行目)に定義しているメソッドです。 ちょっと前後しますが 32/40 行目からの各々の記述は定義であって実行ではありません。 それぞれの()内に書いてあるのは三項演算子もしくは条件演算子と呼ばれるもので、動作としてはコメントされているように ? の前の条件が成立したら ? の後、しなかったら : の後の評価値が選ばれますが、「返す」というのではなく式全体がその評価値として扱われると言うことです。(「1+1 は 2 を返す」のでは無く「1+1 が 2」という感じです。) そして、式は getWriter/getReader メソッドのカッコ内ですので、それらのパラメータ filename への引数となります。 static でない変数云々については、 static とは何なのかと言うことを勉強して頂くしかないです。 回答のコードでは CHARSET_NAME 変数や maind/getWriter/getReader 各メソッドに付いていますし、質問のコードでも main メソッドに付いているのは、意味があってのことです。
jimbe

2023/04/26 03:33

すいません、1つバグがありました。 回答のコードの 41 行目の最後のほうに ", true" が必要でした。 回答のコードを修正します。
moo1211

2023/04/26 04:51

jimbe様 何度もご回答いただきありがとうございます! 家庭教師のようなことをお願いしてしまい申し訳ございません。 >32/40 行目からの各々の記述は定義であって実行ではありません >式は getWriter/getReader メソッドのカッコ内ですので、それらのパラメータ filename への引数となります ↑このあたりが曖昧な理解のままソースを読んでいたので実行順序とかがわかっていませんでしたが理解することができました。また、正直なところstaticやfinalは今まで書いてあっても無視していたのですが、ちゃんと調べて理解できるようにいたします。 このあとソースを修正して実験してみたいと思います、ご回答いただきありがとうございました!
guest

0

itemsのインデックスは1~8ではなくて、0~7です。
お試しください。

投稿2023/04/20 05:13

raikuan

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moo1211

2023/04/20 05:15

ありがとうございます!すぐに試してみます!
moo1211

2023/04/20 05:22

ご指摘いただいた個所を修正したところ正常終了することができました! ご回答いただきありがとうございます。 【出力結果】 B2023012210123456000001234佐藤けん     出力結果をみると1行目(山田太郎のデータ)が出力されていなかったのですが、どのあたりに問題があるかお心当たりございますでしょうか? 何度も質問をして申し訳ございません
raikuan

2023/04/20 05:29

final FileOutputStream os = new FileOutputStream(args[1]); while (reader.ready()) { //.... } os.close(); に編集すればよいと思うんですが。 これは上書き現象ですね。
moo1211

2023/04/20 05:32

何度もご回答、また修正箇所ソースまでいただきありがとうございます、、! このあとすぐ試してみます!
moo1211

2023/04/26 04:53 編集

ご指摘いただいたとおりに修正したところ、上書き現象が解消されました! ありがとうございます!(勘違いをして迷走してました、、) 下記についてもうまくいきました!ありがとうございました!(4/26追記) 【出力結果】 B2023012211234567000012345山田たろう           B2023012210123456000001234佐藤けん     何度も大変申し訳ございません、現在上記のように改行されず一行で出力されており、解消するために改行コードをprintしたり、println("")みたいなのを追記してみたり、+\nみたいなのをやってみたりいろいろと試したのですが実現できませんでした、、 write文のときの改行の仕方がよくわかっておらず、いろいろ検索してみたのですがうまくいきませんでした、、 こちら解決方法や参考になりそうなwebページなどご存じのことございませんでしょうか、、
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問