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

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

ただいまの
回答率

90.50%

  • C#

    7118questions

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

  • Excel

    1536questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。

C#を用いたエクセル操作(書式変換とエクセル解放)

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 736

hiro24

score 4

いつもお世話になっております。

C#の初学者です。

この度は、C#を用いて以下の【目的の動作】を行うウィンドウズフォームアプリを作成する必要が出てきました。
そこで、作成している中で以下の【困っている点】で躓いてしまったため質問を投稿させていただきました。

【開発環境】
・OS:Windows 10
・Visual Studio 2017 ver.15.7.3
・.NET ver.4.7.02556

【目的の動作】
※C#を用いて、以下のエクセル操作を行う※
[1]文字列として保存されている数字を数値に変換したい
[2]文字列として保存されている日付を"yyyy/MM/dd"の日付の書式に変換したい
[3]%の書式で保存されている数値を標準の書式に変換する(例:5.0% ⇒ 0.05) ※もしくは%のみ取って5.0% ⇒ 5.0でも可
[4]ファイルをうまく読み込めなかった際にエクセルの解放の動作が正常に行われる

【困っている点】
[1]C手作業での書式変換のような動作方法をC#で行う方法が不明。
[2]以下のコードを実行すると「Insertできません」というダイアログが表示されて実行できない
[3]以下のコードを実行すると「%が消えない上に5%⇒500%」に変換されてしまう
[4]エラーがあるとプロセスが最後まで実行されずエクセルの開放が行われない

【変換対象】
イメージ説明

【コード】

public partial class Form1 : Form
    {
        public Form1()
        {

        }

        Microsoft.Office.Interop.Excel.Application xlApp = null;
        Microsoft.Office.Interop.Excel.Workbooks xlBooks = null;
        Microsoft.Office.Interop.Excel.Workbook xlBook = null;
        Microsoft.Office.Interop.Excel.Sheets xlSheets = null;
        Microsoft.Office.Interop.Excel.Worksheet xlSheet = null;
        Microsoft.Office.Interop.Excel.Range xlRange = null;
        Microsoft.Office.Interop.Excel.Range xlCells = null;


        private void button1_Click(object sender, EventArgs e)
        {
            openFileDialog1.ShowDialog();

            if (System.IO.File.Exists(openFileDialog1.FileName))
            {

                xlApp = new Microsoft.Office.Interop.Excel.Application();
                xlBooks = xlApp.Workbooks;
                xlBook = xlBooks.Open(openFileDialog1.FileName);
                xlSheets = xlBook.Worksheets;
                xlSheet = xlSheets[1] as Microsoft.Office.Interop.Excel.Worksheet;               

                //[1]convert string to int
                /*******************************************************************/
                                問題点[1]のやり方が不明
                /*******************************************************************/

                //[2]の問題点 convert string to date
                xlCells = xlSheet.Cells;
                xlRange = xlCells[1, 2] as Microsoft.Office.Interop.Excel.Range;

                for (int i = 2; i <= xlSheets[1].UsedRange.Rows.Count; i++)
                {
                    xlRange = xlCells[i, 2] as Microsoft.Office.Interop.Excel.Range;
                    xlRange = xlRange.Insert(4,"/").Insert(7, "/");                   
                }

                //[3]の問題点
                xlRange = xlSheet.Range["C:C"];
                xlRange.Replace("%", "");


                xlBook.SaveAs(@"/*保存先*/");

                //[4]の問題点                
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheets);
                xlBook.Close();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBooks);

                xlApp.Quit();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
            }
            else
            {
                MessageBox.Show("File does not exist. Or it is a non-compliant file.");
            }

        }

    }    

お手数をおかけしてしまい申し訳ございませんが、どなたかお力添えの程頂けないでしょうか。

大変恐縮ですが、よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

Microsoft.Office.Interop.~と名前空間が長くて見にくいので、名前空間エイリアスを使用しましょう。

using ディレクティブ (C# リファレンス) | Microsoft Docs

 [1]文字列として保存されている数字を数値に変換したい

普通に数値に変換して、セルに再代入すればOKです。

イメージ(VBA)

'[1]convert string to int

'対象のセル範囲
Dim toNumberRange As Excel.Range
Set toNumberRange = xlApp.Intersect( _
        xlSheet.UsedRange, _
        xlSheet.Columns.Item("A") _
    )

'セル範囲の値配列(高速化用)
    '速度度外視ならtoNumberRangeをforeachして、各セル直接編集でも可)
Dim toNumValue() As Variant 'object[,]
toNumValue = toNumberRange.Value

Dim r As Long, c As Long
For r = LBound(toNumValue, 1) To UBound(toNumValue, 1)
    For c = LBound(toNumValue, 2) To UBound(toNumValue, 2)
        'value is string and can convert to numeric
        If VarType(toNumValue(r, c)) = vbString And _
           IsNumeric(toNumValue(r, c)) Then

            toNumValue(r, c) = CDbl(toNumValue(r, c)) 'Convert string to double
        End If
    Next c
Next r

'再代入
toNumberRange.Value = toNumValue

 [2]文字列として保存されている日付を"yyyy/MM/dd"の日付の書式に変換したい

[1]と同じです。セルの値を日付に変換してセルに再代入しましょう。
今回は形式が固定のようなのでDateTime.TryParseExactあたりを使えば良いのではないでしょうか。

ところで、Range.Insert メソッド (Excel)はどんな処理か理解していますか?

 [3]%の書式で保存されている数値を標準の書式に変換する

Range.NumberFormatLocal プロパティ (Excel)を設定すれば良いです。

リンク先のサンプルや、
ExcelのVBAのエディタのイミディエイトウィンドウを表示して
?ActiveCell.NumberFormatLocal
などで設定されている文字列がわかるので、「標準」になっているセルと同じ文字列を設定します。

 [4]ファイルをうまく読み込めなかった際にエクセルの解放の動作が正常に行われる

landy77さんが回答されているようにtry catchを使用しましょう。

また全体で使わないのであればMarshal.FinalReleaseComObject メソッド (Object) (System.Runtime.InteropServices)の方が良いかもしれません。

ちょっと古い記事ですが以下も参考に

Office オートメーションで割り当てたオブジェクトを解放する – Part1 – Japan Office Developer Support Blog

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/01 22:56

    ご回答ありがとうございました。
    imihitoさんのご助言のおかげで、[1], [3], [4]の問題は解決することができました。
    しかし、[2]の日付の変換を以下のように試したのですが自分の力不足で上手く実行できませんでした。
    お手数をおかけしてしまい申し訳ございませんが、どこが悪いかご助言いただけないでしょうか。
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Globalization;

    namespace WindowsFormsApp1
    {
    public partial class Form1 : Form
    {
    public Form1()
    {
    InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    Microsoft.Office.Interop.Excel.Application xlApp = null;
    Microsoft.Office.Interop.Excel.Workbooks xlBooks = null;
    Microsoft.Office.Interop.Excel.Workbook xlBook = null;
    Microsoft.Office.Interop.Excel.Sheets xlSheets = null;
    Microsoft.Office.Interop.Excel.Worksheet xlSheet = null;
    Microsoft.Office.Interop.Excel.Range xlRange = null;
    Microsoft.Office.Interop.Excel.Range xlCells = null;

    private void button1_Click(object sender, EventArgs e)
    {
    openFileDialog1.ShowDialog();

    CultureInfo jaJP = new CultureInfo("ja-JP");
    DateTime dateValue;

    try
    {
    if (System.IO.File.Exists(openFileDialog1.FileName))
    {

    xlApp = new Microsoft.Office.Interop.Excel.Application();
    xlBooks = xlApp.Workbooks;
    xlBook = xlBooks.Open(openFileDialog1.FileName);
    xlSheets = xlBook.Worksheets;
    xlSheet = xlSheets[1] as Microsoft.Office.Interop.Excel.Worksheet;

    //[1]convert string to int(解決できました)
    xlRange = xlSheet.Range["A:A"];
    xlRange.NumberFormat = "General";

    //[2]の問題点 convert string to date(未解決)※実行すると例外へ飛んでしまう。
    xlCells = xlSheet.Cells;
    xlRange = xlCells[1, 2] as Microsoft.Office.Interop.Excel.Range;

    for (int i = 2; i <= xlSheets[1].UsedRange.Rows.Count; i++)
    {
    xlRange = xlCells[i, 2] as Microsoft.Office.Interop.Excel.Range;
    if (DateTime.TryParseExact(xlRange.Value, "yyyyMMdd", jaJP, DateTimeStyles.None, out dateValue))
    {
    xlRange.Value = dateValue;
    }
    }

    //[3]の問題点(解決できました)
    xlRange = xlSheet.Range["C:C"];
    xlRange.NumberFormat = "General";

    xlBook.SaveAs(/**/);

    }
    }
    catch
    {
    MessageBox.Show("File does not exist. Or it is a non-compliant file.");
    }
    finally
    {
    //[4]の問題点 (解決出来ました)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheets);
    xlBook.Close();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBooks);

    xlApp.Quit();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
    }

    }

    }
    }

    申し訳ございませんが、今一度お力添えの程お願いいたします。
    よろしくお願いいたします。

    キャンセル

  • 2018/08/01 23:20

    例外の情報を握りつぶしてしまっていますが、具体的にどのような例外が発生したか確認されたでしょうか?
    恐らく`.ToOADate()`あたりで解決するとエスパーしますが、もう少し情報が無いと難しいです

    キャンセル

  • 2018/08/01 23:35

    ご回答ありがとうございます。
    例外の情報記載が漏れてしまい申し訳ございません。

    例外動作ですが、以下のようになります。
    bottonを押すところまでは、実行できています。
    catch
    {
    MessageBox.Show("File does not exist. Or it is a non-compliant file.");
    }
    が実行されて上記のメッセージボックスが表示されて終了する動作になっています。
    それにより、エクセルの中身を変更する動作が何も実行されず(※[4]は実行されました。)終了になっています。

    ちなみに、[1], [3], [4]はこの[2]関連の部分を削除した状態で実行して正常に動作していることは確認しました。

    現状では、このようになっています。

    キャンセル

  • 2018/08/01 23:47

    それはコードを見ればわかる話です
    知りたいのは実行時にしかわからない情報、実際に発生した例外の情報です
    そのcatchで握りつぶした例外の情報(例外の種類・メッセージ・発生行など)をちゃんと確認したかどうかを聞いています

    キャンセル

  • 2018/08/02 22:42

    勘違いしてしまい申し訳ございません。

    63行目に関して以下の警告が出ました。
    if (DateTime.TryParseExact(xlRange.Value, "yyyyMMdd", jaJP, DateTimeStyles.None, out dateValue))←63行目のコード

    'System.DateTime.TryParseExact(string, string, SystemIFormatProvider, System.Globalization.DateTimeStyles, out System.DateTime)'に最も適しているオーバーロードメソッドに無効な引数がいくつか含まれています。

    こちらのような警告が出ておりました。

    キャンセル

  • 2018/08/02 23:11

    そもそもメソッドに渡しているものがおかしい、ということですね。
    恐らくデータ(xlRange.Value)の中に数値が含まれていると思われます。

    明確に文字列であることを確認してから渡す、ということで手は色々あると思いますが
    `xlRange.Value`では無く、`xlRange.Text`でセルに表示されている文字列を取得してTryParseExactに渡すのが一番手軽だと思われます。

    キャンセル

  • 2018/08/02 23:33

    迅速なご回答ありがとうございました。
    ご指摘いただいたとおりに修正いたしましたら、無事に実行できました。

    【修正箇所抜粋】
    for (int i = 2; i <= xlSheets[1].UsedRange.Rows.Count; i++)
    {
    xlRange = xlCells[i, 2] as Microsoft.Office.Interop.Excel.Range;
    if (DateTime.TryParseExact(xlRange.Text, "yyyyMMdd", jaJP, DateTimeStyles.None, out dateValue))
    {
    xlRange.Value = dateValue;
    }
    }

    .Valueは、数値型だったのですね。自分はstring型だと勘違いしておりどうして上記の例外が出てくるのかわからないでいました。
    大変勉強になりました。ありがとうございました。
    また質問をさせていただく機会もあると思いますが、その時は何卒よろしくお願いいたします。

    キャンセル

  • 2018/08/02 23:54

    Excelの`Range.Value`は非常に多くの種類の値を返します。
    ざっと思いつくだけでも以下の値が返される可能性があります。
    String・Double・DateTime・Boolean・object[,]・Int32(エラー)・null

    キャンセル

0

コピペですか?
コピペでも良いですけど、それぞれの行が何をしてるのか理解していけば上の質問はいくつか出てこなくなるはずです。

解放の件は単純にエラー処理を全くしてないからです。
(正直問題外です)
try catch を調べて下さい。

エクセルの操作部分は「c# EXCEL 書式」で一杯出てくるでしょう。

ここら辺までやって「ここまでこうやってみたけどここが分からない。どうわからいのか?」を書いて初めて説明できると思います。

個人的に質問者さんがどういう理由で「必要が出てきた」のかは不明ですけど(答える側としてはどうでもいいですし)、エクセルの操作は全くの初心者の方には若干ハードルが高いと思います。
キャストの件とか一杯他にも知識が必要になりますし・・・・

とりあえず上に記述した所まではもう少し頑張ってみて下さい。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    VB エクセル書き込み

    VB で新規にエクセルを開き,一定時間ごとに変更するリッチテキストボックスやラベルの文字をエクセルのセルに自動で入力させ,エクセルを名前をつけて保存するということをしたいです.

  • 解決済

    C# ファイルの存在チェック

    ファイルの存在チェックにおいて ファイルがある場合に上書き保存をしてファイルを開き、 ファイルがない場合に、用意しておいたファイルをコピーして別名で保存しファイルを開くようにす

  • 受付中

    マクロ実行中のセル入力について

    excelvbaでマクロ実行中に セルに入力をするとマクロがとまってしまいます。 マクロの内容としては、セルの順番にアクティベートにして、 そのセルに入力を出来るようにしたい

  • 解決済

    エクセルのワークシートにあるデータを一つのシートにまとめる。

    タイトルにある質問になります。 現在、エクセルシート内で下記のようなデータがあるシートを 日付順であります。 こちらのシートにあるデータをすべての日付から

  • 受付中

    エクセルでVLOOKUPとループを同時に利用したい

    1つのセル  りんご,バナナ をVLOOKUPとループを利用して 別セルに以下の形式で出力したいです。 <![CDATA[a:2:{i:0;s:1

  • 解決済

    カンマ区切りのデータの重複する要素とその値を合計したい

    閲覧ありがとうございます。 カンマ区切りのデータの重複する要素とその値を合計したいのですが、どのようにすればよいのでしょうか? とても大きなデータなので、excelでは開け

  • 解決済

    [VB.NET]Excelのタスクの消し方

    visual studio2012 でwindowsフォームアプリを作成します。 データグリッドビューのデータをExcelに出力するようにしています。 ですが、Excelを閉じても

  • 受付中

    列を追加したら隣の書式・数式を引き継ぐようにしたい

    仕事で急遽頼まれてしまいましたが、どうしても検索しても見つからなかったため投稿させて頂きます。 今までは抜けている関数を手動で挿入していましたが、自動化をしたいとおもっております。

同じタグがついた質問を見る

  • C#

    7118questions

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

  • Excel

    1536questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。