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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

4回答

1604閲覧

解説をお願いしたいです。

niconicodryyy

総合スコア36

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2019/02/19 05:54

編集2019/02/19 06:57

前提・実現したいこと

学校の課題で言語はC#を利用し開発環境はVisual Studio 2017で任意の読み取ったファイルをバイナリで表示するものを作っていましたが変換の考え方がわからず、結局先生から模範解答を頂きましたが、ファイルを読み取るところまでは理解できますがそこからが理解できません。
ファイルを読み取ってからどのような処理をして、バイナリへと変化させるのでしょうか?
また何故変換したものが規則正しく並ぶのでしょうか?
詳しい方コードの解説ををお願いしたいです。
解説ですが、右も左もわからない状態ですので1から100まで5歳児に教えるように「ここで文字列を取得してここでこういった動作をするからこうなる」と言ったように面倒でしょうが最初から最後まで教えて頂けると幸いです。わからないところはコードにコメントで書いておきました。
今までのコメントは消しました。

先生の作った模範回答なら先生に聞きなさいとの事ですが、この模範解答は今、授業をしていただいてる先生と違う先生が作ったみたいで。詳しい事を聞きに言っても「私のコードじゃないと」逃げられてしまいます。実際に作った先生は誰かわかりません。
また、コード全部とは言わないので「ここからここはどういう意味なんですか?」と言った文法に関する限定的な質問も、現在この課題と違う課題がメインとなっているので、今すべきことをしてくださいと取り合ってくれず、友達も理解できていないので聞ける人がいないのが現状です。
ルール違反をしている場違いな質問かも知れませんが、どなたかお答えいただけると幸いです。

詳しいルールと致しまして。以下の内容となっております。
1、ボタンをクリックしたらファイル参照ダイアログを開いてファイルを選択させる。
2、バイナリー表示するファイル名を表示する。
3、ファイル名を表示した状態でボタンをクリックすると下の表に
左から1.バイトのインデックス 2.ファイル内容をバイナリー表示 3.ファイル内容を1バイトずつ表記する。(全角は文字化け)
と表示し1と2の上には1行0-15バイトまでを表すヘッダーをつけます。
4.ボタンを押したらアプリを終了する。

正常に完了すると以下のようにファイルを表示します。
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 0123456789ABCDEF
00000000 30 31 32 33 34 35 36 37 38 39 0D 0A 82 A0 82 A2 0123456789......
00000010 82 A4 82 A6 82 A8 20 0D 0A 61 62 63 64 65 66 67 ...... ..abcdefg
00000020 68 69 6A 6B 0D 0A hijk..

選択したファイル内容は以下のとおりです。
0123456789
あいうえお
abcdefghijk
以上。質問が多いですがよろしくお願い致します。
*私自身のプログラミングレベルとしてC#歴は1週間程、CとPHPが一ヶ月程となっています。

該当のソースコード

C#

1コード 2 3using System; 4using System.Collections.Generic; 5using System.ComponentModel; 6using System.Data; 7using System.Drawing; 8using System.Linq; 9using System.Text; 10using System.Threading.Tasks; 11using System.Windows.Forms; 12using System.IO; 13 14namespace kadai2 15{ 16 public partial class Form1 : Form 17 { 18 19 public const int ST = 16; 20 21 public Form1() 22 { 23 InitializeComponent(); 24 } 25 26 private void FileSelect_Click(object sender, EventArgs e) 27 { 28 DialogResult dr = openFileDialog1.ShowDialog(); 29 if (dr == DialogResult.OK) 30 { 31 Fname.Text = openFileDialog1.FileName; 32 } 33 } 34 35 36 private void Display_Click(object sender, EventArgs e) 37 { 38 39 if(String.IsNullOrEmpty(Fname.Text)) 40 { 41 DialogResult dr = MessageBox.Show("ファイルが選択されていません。参照ボタンより、ファイルを選択してください。", 42 "メッセージ", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 43 } else 44 { 45 46 DataBox.ResetText(); 47 48 49 header(); 50 51 52 binaryviewer(); 53 } 54 } 55 56 57 private void Close_Click(object sender, EventArgs e) 58 { 59 Close(); 60 } 61 62 private void DataBox_TextChanged(object sender, EventArgs e) 63 { 64 } 65 66 //ここからどいった動きをしているかわかりません。 67    //ここからどいった動きをしているかわかりません。 68     //ここからどいった動きをしているかわかりません。 69 70 private void header() 71 { 72 int i; 73 74 75 for (i = 0; i < 12; i++) 76 { 77 DataBox.Text += " "; 78 } 79 80 81 for (i = 0; i <= 15; i++) 82 { 83 DataBox.Text += string.Format("+{0:X} ", i); 84 if (i == 15) 85 { 86 DataBox.Text += " "; 87 } 88 } 89 90 91 for (i = 0; i <= 15; i++) 92 { 93 DataBox.Text += string.Format("{0:X}", i); 94 if (i == 15) 95 { 96 DataBox.Text += "\r\n"; 97 } 98 } 99 } 100 101 private void binaryviewer() 102 { 103 104 int x = 0; 105 int y = 0; 106 int z = 0; 107 int n; 108 109 FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open); 110 byte[] data = new byte[fs.Length]; 111 fs.Read(data, 0, data.Length); 112 string[] str = new string[fs.Length]; 113 fs.Close(); 114 115 116 while (y < data.Length) 117 { 118 119 DataBox.Text += string.Format("{0:X7}" + '0', x); 120 x++; 121 DataBox.Text += " "; 122 123 while (y < data.Length) 124 { 125 DataBox.Text += string.Format("{0:X2} ", data[y]); 126 y++; 127 128 if (y % ST == 0) 129 { 130 DataBox.Text += " "; 131 break; 132 } 133 } 134 135 136 if ((y == data.Length) && (y % ST != 0)) 137 { 138 for (n = y % ST; n <= ST; n++) 139 { 140 DataBox.Text += " "; 141 } 142 } 143 144 145 while (z < data.Length) 146 { 147 if (data[z] >= 0x20 && data[z] <= 0x7e) 148 { 149 DataBox.Text += (char)data[z]; 150 z++; 151 } 152 else 153 { 154 str[z] += "."; 155 DataBox.Text += str[z]; 156 z++; 157 } 158 159 if (z % ST == 0) 160 { 161 DataBox.Text += "\r\n"; 162 break; 163 } 164 } 165 } 166 } 167 168 private void Form1_Load(object sender, EventArgs e) 169 { 170 171 } 172 } 173}

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

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

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

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

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

dice142

2019/02/19 05:58

模範解答の説明はコードレビューではなく解説そのものです。 模範解答を作成した先生に聞くのが一番手っ取り早いし正確なので、先生に聞いてはいかがでしょう? (なぜ半角カタカナなのかという疑問もあるけど)
m.ts10806

2019/02/19 06:00

非推奨です。 https://teratail.com/help/avoid-asking >コードをください・デバッグしてください等の丸投げの質問 簡単に「コードレビューしてください」と仰っているように見受けられますが、あなたに課題を与えたわけでもない全くの赤の他人にレビュー依頼するっておかしいと思いませんか?
papinianus

2019/02/19 06:38 編集

これが"模範回答"ということですか? 説明をしようと思ったんですが、コメントついてるし、このコードはとても参考にならないので、どのあたりが分からないか具体化していただけませんか?
azuapricot

2019/02/19 06:05

・ここはコードレビューサイトではありません ・コードを貼りつけるときはマークダウン <code> を使用してください ・半角カタカナが好きなのかなんなのかしりませんが読みにくいことこの上ないので全角カナで書きましょう まぁここで聞くのが間違っています。 先生から模範解答をもらったのなら、先生が作ったコード、ということですよね? なら先生に聞きましょう。
cateye

2019/02/19 06:30 編集

コードレビューは、先生相手か仲間とやりましょうd^^ あと、“あいうえお”のあとに空白が入っていますよd^^・・・表示がおかしいのか、ファイルがおかしいのか? 分かりますか?
Q71

2019/02/19 06:28

文字列の+演算子使うな。StringBuilder使え。 STの宣言しているんだからマジックナンバー15使うな。 当然、コメントも「15バイト」じゃなく「ST-1バイト」。 半角?なにそれ?(大昔ですが、「半角文字だけ使え」と言ったらワープロで漢字を半角表示してデータ入力してきやがったアホがいた) レビュー:見直し、検討 あなたが望んでいるのは「解説(コメント)」では?
Stan_Dma

2019/02/19 07:22 編集

Code review means that is one of the software developing phase to review some codes, to verify its correctness, effectiveness ,also not vulnerable and so on, in accordance with its specification. The questioner have used the term incorrectly. So do the repliers except Q71-san for good advice as reviewer.
azuapricot

2019/02/19 06:53

えぇ~・・・コードの中にも半角文字入れてるんですか・・・ コーダーとしてそれは本当やめたほうがいいですよ。 現場では誰もそんな書き方してる人いません。 オンラインゲームとかでは半角カタカナがかわいく見えたりして好んで使う学生さんがいますが(最近みないけど)、 もう半角カナは卒業しましょう。
azuapricot

2019/02/19 06:56

あと、確かに質問者さんは「コードレビュー」の意味を間違えてますね。 コードレビューは解説ではないです。 できる人に見てもらって、「ここを直したほうがいいんじゃない?」とか言ってもらうことです。 コード見てませんでしたが、コメントで書いてある通り 「処理がなにやってんのかわからん」 なら解説してほしいんですよね? コードレビューじゃないですね。
m.ts10806

2019/02/19 07:18

解説依頼でも結局「作ったのが自分でなければ作った人に聞いてね」って話になりますけどね。自分ならなおさら「なんで人に説明できないコード作ったの?」ですし。
m.ts10806

2019/02/19 07:20

あと、言っちゃ悪いですが5歳児を馬鹿にしすぎですね。
guest

回答4

0

概ね補足依頼の通りですが、少々。

今後ITの世界に関与するのであれば、通称「半角文字」と呼ばれる「ボタン」のような文字(濁点や半濁点が1文字になっているのが特徴の横幅の狭い文字)は使わない方が無難です。そもそも、ひらがなとカタカナで文字幅が違うもの混在しているということに違和感を覚えないようだと、プログラミング以前にこういう場も含めた文章の見栄えや、読んでもらえる文章を書くという点で損をしますし、そういう人が書くプログラムは総じて「汚く」なります。

それから、質問文のプログラムを貼り付けている部分、他の人の質問と見た目が違いませんか?他の人の質問文では、プログラムの文字がわかりやすく色分けされていたりしていませんか?

これは質問文を書くときの書き方次第で、きちんと整形して色分けする機能がこのサイトに用意されていて、それを使うことがこの場では推奨されているからです。こういう「自分が書いた物や作った物が、どうも他と違うぞ!?」という点に気づいて「なんで?」という疑問をもつようにならないと、いくらコードレビューで指摘されても、指摘されたパターン以外に応用したり、類似した部分を将来自分でよりよくしたりするといった能力につながりません。また、習ったこと以上の事を自分で身につける能力も得られません。

ちなみに、teratailのQA文で使える記法はMarkdownというもので、現在結構使われるようになっているので、少し調べてみられることをお勧めします。その場その場に応じたルールをさっと見抜いて適応する、というのも、プログラムを作る上で重要になることがあります(仕事で作る人は、職場やチームによってルールが違ったりします。そういう周りに合わせる能力も必要な場面があります)。

本来このような回答をする場ではありませんが、ちょっと目に余るので書きました。おそらく期待された回答ではないと思いますが、何かの参考になれば幸いです。

投稿2019/02/19 06:46

編集2019/02/19 06:48
backyard

総合スコア534

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

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

0

詳しい事を聞きに言っても「私のコードじゃないと」逃げられてしまいます。

じゃぁ、「「先生」を名乗らないでください」としか。
昔、食器屋でアルバイトをしていました。お客様より、「このお椀は、集成材ですか」と聞かれました。わからなかったので「アルバイトなのでわかりません」と答えたところ、「アルバイトでも、お店の代表として接客にあたるのだから、知っていてください」と叱られました。
このやりとりの是非についての判断はお任せします。しかし、仕事をする上での責任について、学んでください。「模範解答」として配るのであれば、その内容について答えられなければなりません。

今すべきことをしてくださいと取り合ってくれず

「すべきことをするための前提が理解できていなければ、すべきことができません。」と、食い下がってください。

DataBox が何かわかりません。DataBox.ResetText で、テキストがクリアされると前提します。
DataBox.Textstring クラスで、これの内容が画面に表示されると前提します。
.NET Framework では、文字列の結合に + 演算子を使わないでください。
.NET Framework では、文字列は不変です。"a" + "b" + "c" は、"ab" という文字列と、式の最終出力としての "abc" という文字列が作られます。つまり、大きな文字列の連結は、それだけメモリを消費します。従って、複数回文字列を連結する場合は StringBuilder クラスを使います。
変数をメソッドの最初で定義しておくのは、古い(1990年代までの)C言語の流儀。
C# では、使い始める直前に宣言する。

private void header() { // いや、これは、for (int i ... と毎回打ってくれ。 int i; // 12個の空白を追加します。 // string.Format("{0,12}", " ")の1行でいいかと。 for (i = 0; i < 12; i++) { DataBox.Text += " "; } // string.Format は、第一引数のフォーマットの文字列を作ります。 // 第二引数以降は、フォーマット中の書式指定子に入れるオブジェクトです。 // {0:X} は、0番目の引数(第一引数より後の引数のインデックスなので、第二引数)を Hexagram で、かつ、アルファベットは大文字にして割り当てます。 // https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/standard-numeric-format-strings#the-hexadecimal-x-format-specifier // なんで i <= 15 なのか、わからん。どうせ「ここのループが終わったら、間を開ける」なんやから、 // for (i = 0; i < 16; i++) // { // 省略 // } // DataBox.Text += " "; // でええやん。 for (i = 0; i <= 15; i++) { DataBox.Text += string.Format("+{0:X} ", i); if (i == 15) { DataBox.Text += " "; } } // "\r\n" は、Windows での改行。 // タイプライターで、打刻している内に左へずれた紙を右へ戻す「復帰」と、「行送り」の2文字。 // OS によって「改行」文字は異なるので、ネットワークを扱うときは注意。 for (i = 0; i <= 15; i++) { DataBox.Text += string.Format("{0:X}", i); if (i == 15) { DataBox.Text += "\r\n"; } } } private void binaryviewer() { // ここに、変数の使い道をコメントしておく。 int x = 0; // C言語ではこの位置 // 読み込んだデータのうち、表示中の文字インデックス。 int y = 0; int z = 0; int n; // FileStream は IDispose インターフェイスを実装しているので、using 句を使うのが望ましい。 // using (FileStream fs = ...) // { // byte[] data = ... // } FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open); byte[] data = new byte[fs.Length]; fs.Read(data, 0, data.Length); string[] str = new string[fs.Length]; fs.Close(); while (y < data.Length) { // 意図不明。("{0:X7}0", x) で良いのでは? // つーか、これ、あかんやろ。y と一緒に足して行けや。 // ちゃうか。この時点の y.ToString("X8") でええやん。 DataBox.Text += string.Format("{0:X7}" + '0', x); x++; DataBox.Text += " "; // y が data.Length より小さい間繰り返す。 // ここは if (y % ST == 0) があるので、ST 回ずつ繰り返す。 while (y < data.Length) { // data の y 番目を "xx " の書式で追加していく。 DataBox.Text += string.Format("{0:X2} ", data[y]); y++; if (y % ST == 0) { // y を ST で割ったあまりが 0 ならば、 // 間を開ける。 DataBox.Text += " "; break; } } if ((y == data.Length) && (y % ST != 0)) { // y が data.Length に等しい、つまりデータのすべてを表示した、かつ、y が ST の倍数ではないなら、 // 足りない分を埋める。 for (n = y % ST; n <= ST; n++) { DataBox.Text += " "; } } // 文字として表示する部分 // やってることは上と同じ while (z < data.Length) { // ここで「印字可能文字」を 0x20~0x7E とし、この範囲の文字のみ印字する。 // 正確には、データのコードページを調べてそれぞれのリーディングバイトをマークして、トレイリングバイトも表示しないようにする。 // それは面倒なので、「(全角は文字化け)」 if (data[z] >= 0x20 && data[z] <= 0x7e) { DataBox.Text += (char)data[z]; z++; } else { str[z] += "."; DataBox.Text += str[z]; z++; } if (z % ST == 0) { DataBox.Text += "\r\n"; break; } } } } private void Form1_Load(object sender, EventArgs e) { }

投稿2019/02/19 12:01

編集2019/02/27 12:58
Q71

総合スコア995

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

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

0

ベストアンサー

#回答趣旨

説明は出たので

詳しい事を聞きに言っても「私のコードじゃないと」逃げられてしまいます。

のところについての対策を回答とさせていただきたいです

なぜ私のコードじゃないと言われてしまうか

訳がわからないコードだからです。先の解説回答からも推測できると思いますが、根本的にC#っぽくない。パラダイムが分かってない。宣言的でない。副作用が酷すぎる。無駄にループしている。無駄に意味の分からない条件判定している。
まとめると、全部の動きがわかっている人しか読めないようなコードになっているので、分からない人にとってはとても分かりにくいコードになっています。意図して分かりにくく書いているとさえ感じます。

具体例

  • mainform.cs

formにはボタン(ダイアログ起動用)、textbox(パス表示用)、textbox(=DataBox,内容表示用)があります。

csharp

1using System; 2using System.Windows.Forms; 3using System.IO; 4 5namespace BinaryReader 6{ 7 public partial class MainForm : Form 8 { 9 public MainForm() 10 { 11 InitializeComponent(); 12 } 13 14 private void SelectFileButtonClick(object sender, EventArgs e) 15 { 16 var filePath = SelectFileDialog(); //Dialog起動 17 if(string.IsNullOrEmpty(filePath)) { return; } //空だったら何もしない 18 SelectedFile.Text = filePath; // パス表示 19 DataBox.ResetText(); //テキストボックスリセット 20 DataBox.Text = string.Join(string.Empty, Format.Lines(File.ReadAllBytes(filePath))); //テキストを全部バイト配列にして、フォーマッタにわたして、返り値をDataBoxに入れる。もともと全部読んでるしお勉強の範囲なんで、ReadAllBytesでいいでしょ。 21 } 22 private string SelectFileDialog() //filedialogを起動して名前(フルパス)を返します。 23 { 24 var result = FileDialog.ShowDialog(); 25 if(result == DialogResult.OK) 26 { 27 return FileDialog.FileName; 28 } 29 return string.Empty; 30 } 31 } 32}
  • format.cs

整形して文字列にしてくれるユーティリティ

csharp

1using System; 2using System.Collections.Generic; 3using System.Linq; 4 5namespace BinaryReader 6{ 7 internal static class Format 8 { 9 private const int hex = 16; 10 private const string sep = " "; 11 internal static IEnumerable<string> Lines(IReadOnlyCollection<byte> bytes) 12 { 13 // "<8digit><4s>X2 X2 X2 X2 X2 X2 X2 X2 X2 X2 X2 X2 X2 X2 X2 X2<4s>< 16 chars >" 14 //1行目としてヘッダ。こんな変動しないものをいちいちforで作らない 15 yield return $" {sep}+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F{sep}0123456789ABCDEF{Environment.NewLine}"; 16 //IxのBufferで16ずつのまとまりにして、foreachする。このときindexをつければxとかyとかを自分で管理する必要は全くない 17 foreach (var line in bytes.Buffer(hex).Select((bs, i) => (idx: i, bytes:bs))) 18 { 19 //バイト表記部分。配列の1要素をX2にフォーマット。16個になるように調節しています 20 var byteExpressions = line.bytes.Select(b => $"{b:X2}").Concat(Enumerable.Repeat(" ", hex)).Take(hex); 21 //アスキー表記部分。配列の1要素をcharに変換。訳がわからんifじゃなくて、IsLetter/IsDigitをつかえば判断できるはず。こちらも16個になるように調節しています 22 var charExpressions = line.bytes.Select(b => char.IsLetter((char)b) || char.IsDigit((char)b) ? (char)b : '.' ).Concat(Enumerable.Repeat(' ', hex)).Take(hex); 23 //Bufferのindexから求めた数値と、バイト表記と、アスキー表記をならべれば、欲しい1行が得られるはず 24 yield return $"{line.idx:X7}0{sep}{string.Join(" ",byteExpressions)}{sep}{string.Join(string.Empty, charExpressions)}{Environment.NewLine}"; 25 } 26 } 27 } 28}

どう考えても1つのループで終わる処理を、while->while->if/elseみたいに3段階もネストして状態変数を何個もつかってりゃそりゃ他の先生も逃げ出したくなるよねっていう話じゃないですかね。
(可読性を無視して説明変数を排除すれば、多分ワンライナーにできます。こういう副作用を必要としない処理を手続的に書いちゃだめです)

動かすにはこちらをcloneしてみてくださいな

投稿2019/02/20 06:01

papinianus

総合スコア12705

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

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

0

したが、ファイルを読み取るところまでは理解できますがそこからが理解できません。

ファイルを読み取ってからどのような処理をして、バイナリへと変化させるのでしょうか?

本当にファイルを読み取るところまで理解してるんですか?

FileStreamを使ってbyte配列に読み込んだ時点でバイト単位のデータになっています。
その配列の各要素を16進数文字列として表示すればいいだけです。

投稿2019/02/19 08:54

PineMatsu

総合スコア3579

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問