C#(コンソール) : ODBC 経由のデータベースの読込み

コンソールから、Windows UI である『ファイル参照ダイアログ』を使用する為に、System.Windows.Forms を参照して [STAThread] を記述しています



概要

ファイル選択をキャンセルした場合は、最初に設定した MySQL に対してアクセスします。ファイル選択で、.xls か .xlsx か .mdb が .accdb を選択すると、それをデータベースとしてアクセスします。
using System;
using System.Data.Odbc;
using System.Diagnostics;
using System.Windows.Forms;

namespace DBAccess
{
	class Program
	{
		[STAThread]
		static void Main(string[] args)
		{
			// データベースアクセスに必要なクラス
			OdbcConnection myCon;
			OdbcCommand myCommand;
			OdbcDataReader myReader;

			// ODBC 接続文字列作成用のクラス
			OdbcConnectionStringBuilder builder = new OdbcConnectionStringBuilder();

			// *******************************************
			// インストールされているドライバ文字列
			// 初期は MySQL として準備する
			// *******************************************
			builder.Driver = "MySQL ODBC 8.0 Unicode Driver";
			// builder.Driver = "MySQL ODBC 5.3 Unicode Driver";

			// 接続用のパラメータを追加
			builder.Add("SERVER", "localhost");
			builder.Add("DATABASE", "lightbox");
			builder.Add("UID", "root");
			builder.Add("PWD", "");

			// 接続文字列の内容を確認
			Console.WriteLine(builder.ConnectionString);

			// System.Windows.Forms の参照が必要です
			OpenFileDialog ofd = new OpenFileDialog();

			// *******************************************
			// ファイル選択した場合はその DB を使用する
			// *******************************************
			ofd.Filter = "AccessとExcel|*.mdb;*.accdb;*.xls;*.xlsx|すべてのファイル(*.*)|*.*";
			ofd.FilterIndex = 1;
			ofd.Title = "データベースを選択してください";
			ofd.RestoreDirectory = true;
			// 選択した場合は再設定する
			if (ofd.ShowDialog() == DialogResult.OK)
			{
				// リセット
				builder.Clear();
				// 拡張子文字列の簡易チェックで Excel か Access が判断する
				if (ofd.FileName.ToLower().IndexOf(".xl") != -1 )
				{
					// インストールされているドライバ文字列
					builder.Driver = "Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)";
				}
				else
				{
					builder.Driver = "Microsoft Access Driver (*.mdb, *.accdb)";
				}

				// 接続用のパラメータを追加
				builder.Add("dbq", ofd.FileName);
			}

			// *******************************************
			// 新しい OdbcConnection オブジェクトを作成
			// ( using で使用後の自動解放を行う )
			// https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/using-statement
			// ※ 接続を持続したい場合は using は使わない
			// *******************************************
			using (myCon = new OdbcConnection())
			{

				// 接続文字列を設定
				myCon.ConnectionString = builder.ConnectionString;

				// 接続処理
				try
				{
					// 接続
					myCon.Open();
				}
				catch (OdbcException ex)
				{
					// エラー内容( パスワード等でテストする )
					Console.WriteLine($"Console : {ex.Message}");
					Debug.WriteLine($"Debug : {ex.Message}");
				}

				// 接続に失敗している場合は終了
				if (myCon.State != System.Data.ConnectionState.Open)
				{
					// 終了前に停止
					Console.ReadLine();
					return;
				}

				// *******************************************
				// 接続が完了したので読み出しの準備
				// ▼ 実行する SQL
				// *******************************************
				string myQuery = "select * from 社員マスタ";

				using (myCommand = new OdbcCommand())
				{
					// 実行する為に必要な情報をセット
					myCommand.CommandText = myQuery;
					myCommand.Connection = myCon;

					// *******************************************
					// 接続と SQL を使用して列データを取り出す
					// https://docs.microsoft.com/ja-jp/dotnet/api/system.data.odbc.odbcdatareader
					// *******************************************
					using (myReader = myCommand.ExecuteReader())
					{

						Console.WriteLine($"定義されている列の数 : {myReader.FieldCount}");

						// *******************************************
						// 列名の一覧
						// *******************************************
						for (int i = 0; i < myReader.FieldCount; i++)
						{
							if (i != 0)
							{
								Console.Write(",");
							}
							Console.Write(myReader.GetName(i));
						}
						// 改行
						Console.WriteLine();

						// *******************************************
						// データ型の一覧
						// *******************************************
						for (int i = 0; i < myReader.FieldCount; i++)
						{
							if (i != 0)
							{
								Console.Write(",");
							}
							Console.Write(myReader.GetDataTypeName(i));
						}
						// 二つの改行 
						Console.WriteLine("\n");


						// *******************************************
						// カンマ区切り( CSV ) で出力
						// *******************************************
						while (myReader.Read())
						{
							// 文字列
							Console.Write($"{GetValue(myReader, "社員コード")},");
							Console.Write($"{GetValue(myReader, "氏名")},");
							Console.Write($"{GetValue(myReader, "フリガナ")},");
							// 整数
							Console.Write($"{GetValue(myReader, "給与")},");
							Console.Write($"{GetValue(myReader, "手当")},");
							// 日付
							Console.Write($"{GetValue(myReader, "作成日").Substring(0, 10)},");
							Console.Write($"{GetValue(myReader, "更新日")},");
							Console.Write(GetValue(myReader, "生年月日"));

							// 改行
							Console.WriteLine();

						}

						myReader.Close();

					}

					// OdbcCommand に Close はありません
				}

				// 接続解除
				myCon.Close();
			}

			// 終了確認用
			Console.WriteLine("\n処理が終了しました");

			// 終了前に停止
			Console.ReadLine();
		}

		// *******************************************
		// データを列名文字列で取り出す関数
		// *******************************************
		static string GetValue(OdbcDataReader myReader, string strName)
		{

			string ret = "";
			int fld = 0;

			// 指定された列名より、テーブル内での定義順序番号を取得
			fld = myReader.GetOrdinal(strName);
			// 定義順序番号より、NULL かどうかをチェック
			if (myReader.IsDBNull(fld))
			{
				ret = "";
			}
			else
			{
				// NULL でなければ内容をオブジェクトとして取りだして文字列化する
				ret = myReader.GetValue(fld).ToString();
			}

			// 列の値を返す
			return ret;

		}
	}
}


関連する記事

32ビット ODBC ドライバの一覧を取得する



C#

WindowBuilder( SWT ) : テキストファイルを読み込む

WindowBuilder のインストールとプロジェクトの作成は 『Pleiades Eclipse 4.7 Oxygen : SWT(Table) + MySQL の SQL(SELECT) で一覧表示』を参照して下さい。

C# と同時並行で Java を勉強するのならば、WindowBuilder がおすすめです。JavaFX は情報が少なすぎるのでプロになってから使えばいいと思います。Java そのものの学習には、これと AndroidStudio で簡単なスマホアプリを作れば十分です。

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;

import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class FormOpenText extends ApplicationWindow {
	private Text text;

	// *********************************
	// コンストラクタ
	// *********************************
	public FormOpenText() {
		super(null);
		createActions();
	}

	// *********************************
	// コントロールの追加
	// ※ Design での変更が反映されます
	// *********************************
	@Override
	protected Control createContents(Composite parent) {
		Composite container = new Composite(parent, SWT.NONE);

		// *********************************
		// ボタン
		// *********************************
		Button btnNewButton = new Button(container, SWT.NONE);
		btnNewButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {

				// *********************************
				// ボタンのイベント
				// *********************************
				MessageBox mb = new MessageBox((Shell) parent, SWT.OK|SWT.CANCEL);
				mb.setText("テキスト");
				mb.setMessage("メッセージ");

				int result = mb.open();
				if (result == SWT.OK ) {

					System.out.println("OK");

					String path = "c:\\User";
					String[] filterExt = { "*.txt;*.csv;*.log", "*.*" };
					String[] filterNames = { "テキストファイル", "全て" };

					FileDialog fd = new FileDialog((Shell) parent,SWT.OPEN);
					fd.setFilterPath(path);
					// https://www.programcreek.com/java-api-examples/?class=org.eclipse.swt.widgets.FileDialog&method=setFilterExtensions
					fd.setFilterExtensions(filterExt);
					fd.setFilterNames(filterNames);

					String target = fd.open();
					if (target != null) {
						try {
							BufferedReader buffer = new BufferedReader(
									new InputStreamReader(
											new FileInputStream(target),
											"SJIS"));

							// 一行ぶんの文字列
							StringBuilder textData = new StringBuilder();
							String line_buffer;

							while ( null != (line_buffer = buffer.readLine() ) ) {
								// メモリルに出力
								textData.append( line_buffer + "\r\n" );
							}

							buffer.close();

							// 画面のテキストエリアにセット
							text.setText(textData.toString());

						} catch (Exception ex) {
							ex.printStackTrace();
						}
					}
				}
				if (result == SWT.CANCEL ) {
					System.out.println("CANCEL");
				}
			}
		});
		btnNewButton.setBounds(10, 10, 75, 25);
		btnNewButton.setText("New Button");

		// *********************************
		// テキストエリア
		// *********************************
		text = new Text(container, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
		text.setBounds(10, 47, 414, 200);

		return container;
	}

	// *********************************
	// 初期処理
	// *********************************
	private void createActions() {

	}

	// *********************************
	// 開始
	// *********************************
	public static void main(String args[]) {
		try {
			FormOpenText window = new FormOpenText();
			window.setBlockOnOpen(true);
			window.open();
			Display.getCurrent().dispose();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// *********************************
	// アプリケーションウインドウ設定
	// *********************************
	@Override
	protected void configureShell(Shell newShell) {
		super.configureShell(newShell);
		newShell.setText("New Application");
	}

	// *********************************
	// Window サイズの初期設定
	// ********************************
	@Override
	protected Point getInitialSize() {
		return new Point(450, 300);
	}
}





HTA か IE11(要設定) で動作する Excel.Application の処理を JavaScript で記述したサンプル

JavaScript で記述しているのは、jQuery を使用したいからです。Excel 部分以外であれば他の用途にそのまま利用できるように考えています。

twitter-bootstrap を使用して簡単で美しい見栄えが利用できます。

Excel.Application を JavaScript で利用する際は、Microsoft が認識しているバグがあるので、サンプルのような終わり方をする必要があります。そうしなければ、メモリに Excel のプロセスが残ってしまう事を避けられません。Microsoft は、VBScript を使えば問題無いと書いていますが、IE11 でそもそも VBScript を使うのはいろいろ制限や工夫が必要な上に他へのリソースの流用ができないので、このようなアプローチが必要かもしれません。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta charset="sjift_jis">
<title>Excel の処理</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.css" />
<script>

	// ****************************
	// HTA の時のみ使用
	// ****************************
	//top.moveTo( 300, 150 );
	//top.resizeTo( 800, 600 );

	var WshShell = new ActiveXObject("WScript.Shell");
	var FilePath = "";

	$(function(){

		$("#action").on("click", function(){

			// ****************************
			// Excel.Application を解放する為に
			// ローカル変数を使用しています
			// ****************************
			var Excel = null;
			var Book = null;
			var Worksheet = null;

			Excel = new ActiveXObject("Excel.Application");

			// ****************************
			// 保存ダイアログを前面に
			// 表示する為の処理です
			// ****************************
			Excel.Visible = true;
			Excel.WindowState = 2;	// Minimize
			Excel.WindowState = 1;	// Maximize
			Excel.Visible = false;

			// ****************************
			// 警告を出さないようにする
			// 使用すると上書きの警告が
			// 出なくなります
			// ****************************
			// Excel.DisplayAlerts = false;

			// ****************************
			// ブック追加
			// ****************************
			Excel.Workbooks.Add();

			// ****************************
			// 追加したブックを取得
			// ****************************
			Book = Excel.Workbooks( Excel.Workbooks.Count );

			// ****************************
			// 現状、ブックにはシート一つ
			// という前提で処理していますが
			// 必要であれば、Book.Worksheets.Count
			// で現在のシートの数を取得できます
			// ****************************
			Worksheet = Book.Worksheets( 1 );
			Worksheet.Activate();

			// ****************************
			// シート名設定
			// ****************************
			Worksheet.Name = "新しい情報";

			// ****************************
			// 参照
			// 最後の 1 は、使用するフィルター
			// の番号です
			// ****************************
			FilePath = Excel.GetSaveAsFilename( "excel_001","Excel ファイル (*.xlsx), *.xlsx", 1)
			if ( FilePath == false ) {
				// ****************************
				// 保存していないので
				// 保存した事にして閉じます
				// ****************************
				Book.Saved = true;
				Book.Close();
				Excel.Quit();
				Excel = null;

				alert( "Excel ファイルの保存選択がキャンセルされました" );

				window.setTimeout("Cleanup();",1);
				return;
			}

			// ****************************
			// セルへセット
			// ****************************
			// タイトル部分の参照
			$("#tbl th").each(function(idx){
				Worksheet.Cells(1, idx+1) = $(this).text();
			});

			// 行一覧の参照
			$("#tbl tr").each(function(row){
				$(this).find("td").each(function(idx){
					Worksheet.Cells(row, idx+1) = $(this).text();
				});
			});

			// ****************************
			// セルをデータに合わせて
			// 整理して左上を選択
			// ****************************
			Worksheet.Columns("A:C").Select();
			Worksheet.Columns("A:C").EntireColumn.AutoFit();
			Worksheet.Range("A1").Select();

			// ****************************
			// 保存
			// 拡張子を .xls で保存するには
			// Call ExcelBook.SaveAs( FilePath, 56 ) とします
			// ****************************

			try {
				Book.SaveAs( FilePath );
			}
			catch (e) {
				console.dir(e);
				alert("Book.SaveAs でエラーが発生しました");
			}

			// ****************************
			// Excel をアプリケーションとして終了
			// ****************************
			Excel.Quit();
			Excel = null;
			idTmr = window.setTimeout("Cleanup();",1);

			alert("処理が終了しました \n\n 保存したブックを開きます");

			WshShell.Run( "RunDLL32.EXE shell32.dll,ShellExec_RunDLL " + FilePath );

		});

	});

function Cleanup() {
	CollectGarbage();
}
</script>

<style>
html,body {
	/* height: 100%; */
}

.entry td {
	padding: 6px;
}

/* ****************************
テーブル内のデータを選択不可
( ダブルクリック対応 )
******************************/
#tbl {
	user-select: none;
	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
}

#tbl th {
	cursor: default;
}

#tbl td {
	cursor: default;
	color: black;
}

</style>

</head>
<body>
<div class="main">

<table class="entry ml-3 mt-3">
	<tr>
		<td>
			<input id="action" type="button" value="Excel.Application の実行" class="form-control btn btn-primary">
		</td>
	</tr>
</table>


<table class="table ml-3 mt-2" id="data" style='width:400px;'>

	<tbody id="tbl">

		<tr>
			<th>コード</th>	<th>開始日</th>	<th>終了日</th>
		</tr>

		<tr>
			<td>FIRST</td><td>2018/04/01</td><td>2018/06/30</td>
		</tr><tr>
			<td>SECOND</td><td>2018/07/01</td><td>2018/09/30</td>
		</tr><tr>
			<td>THIRD</td><td>2018/10/01</td><td>2018/12/31</td>
		</tr><tr>
			<td>FOURTH</td><td>2019/01/01</td><td>2019/03/31</td>
		</tr>

	</tbody>

</table>


</div>
</body>
</html>


関連する記事

🔻 IE11 の設定と VBScript でのサンプルです
IE11 で Excel のブックにアクセスする / JavaScript を使用して Excel のブックのセルにデータをセットして更新



C# コンソールアプリを AN HTTPD で実行して WEB の根本を学ぶ

AN HTTP Server の使用方法

単純に、WEB アプリケーション初心者にブラウザとサーバーのやり取りを知ってもらう為に( 今は、開発者ツールがあるので途中の解説がしやすいですし )、C# で作った EXE をそのままブラウザで実行させます。

基本設定

EXE の列の『一般パスでも実行する』にチェックします



次に、一般パスに C# で作成された Debug フォルダを登録します。



後は、loclhost から実行するだけです。

ソースコード
using System;
using System.Collections;
using System.Text;
using System.Web;

namespace cgi_test
{
	class Program
	{
		static void Main(string[] args)
		{
			string formtype = "POST";

			string[] param = { };

			// ******************************
			// Console.WriteLine を UTF8 で
			// ******************************
			Console.OutputEncoding = Encoding.UTF8;

			// ******************************
			// メソッド
			// ******************************
			string method = Environment.GetEnvironmentVariable("REQUEST_METHOD");

			// ******************************
			// GET
			// ******************************
			if (method == "GET")
			{
				// ******************************
				// QUERY_STRING
				// ******************************
				string query_string = System.Environment.GetEnvironmentVariable("QUERY_STRING");
				// URL のみの場合はデータ無しの QUERY_STRING を用意する
				if (query_string == "" )
				{
					query_string = "field1=&field2=";
				}

				// & で分割して key=value の文字列の配列を作成する
				param = query_string.Split('&');
			}

			// ******************************
			// POST
			// ******************************
			if (method == "POST")
			{
				string line;

				// POST 時は必ず key=value の文字列が存在する
				line = Console.ReadLine();
				param = line.Split('&');
			}

			// = で区切って key と value が配列の 0 と 1 にセットされる
			string[] key_value = { };

			// ******************************
			// key と value の格納
			// ******************************
			Hashtable field = new Hashtable();

			foreach (string key_value_set in param)
			{
				key_value = key_value_set.Split('=');
				// key がある場合は、Hashtable に格納する
				if (key_value[0] != "") {
					// System.Web を参照して using System.Web; で HttpUtility.UrlDecode
					// %エンコードを元に戻す
					field.Add(key_value[0], HttpUtility.UrlDecode(key_value[1]));
				}
			}

			// ******************************
			// HTTP ヘッダ
			// PHP の session_cache_limiter
			// ******************************
			Console.WriteLine("Content-Type: text/html; charset=utf-8");
			Console.WriteLine("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
			Console.WriteLine("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
			Console.WriteLine("Pragma: no-cache");
			Console.WriteLine();

			string message = "<div>こんにちは世界</div>";

			// ******************************
			// HTML
			// $ で変数埋め込みのヒアドキュメント
			// ******************************
			string html = $@"<!DOCTYPE html>
<html>
<head>
</head>
<body>
{message}
<form method='{formtype}'>
<p>氏名 : <input type='text' name='field1' value='{field["field1"]}'></p>
<p>フリガナ : <input type='text' name='field2' value='{field["field2"]}'></p>
<p>送信 : <input type='submit' name='send' value='送信'></p>
</form>
</body>
</html>";

			// 作成した HTML を出力する
			Console.WriteLine(html);
		}
	}
}





C# : 現在実行中のパスのファイルの一覧をテキストファイル(UTF8N)に出力する

Microsoft のドキュメントに 方法: ディレクトリとファイルを列挙する というページがあります。そこでは、Directory.EnumerateDirectories を使用したサンプルですが、 List クラスに変換してから foreach を使用しています。

foreach を使用して一覧を取得するだけならば、戻り値の IEnumerable をそのまま使用しても問題無いですが( Directory.EnumerateFiles のサンプルはそのまま使用している )、一般的な認識として List クラスを使用したほうが良いと思います。

※ IEnumerable は Interface であり、クラスを新たに作成する時に使用するものです
※ $ は、文字列補間
※ @ は、逐語的識別子として機能します

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace file_list
{
	class Program
	{
		static void Main(string[] args)
		{
			// 現在実行中のパス
			string cur_path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

			// 文字列補間 / https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/tokens/interpolated
			Console.WriteLine( $"現在実行中のパスは {cur_path} です" );

			// **********************************************
			// 一覧処理は、IEnumerable のままでも可能ですが、
			// 一般的なコードとして処理する為に 
			// List クラスを使用します
			// **********************************************
			List<string> files = new List<string>(Directory.EnumerateFiles(cur_path, "*", SearchOption.TopDirectoryOnly));

			// 情報を一括で処理する為に文字列としてメモリに保存します
			StringBuilder file_list = new StringBuilder();

			foreach ( string name in files)
			{
				// ファイルのパスを追加
				file_list.Append(name);
				// 改行を追加
				file_list.AppendLine();
			}

			// コマンドプロンプトに表示
			Console.Write(file_list.ToString());

			// 同じ内容をテキストファイルに UTF8N で書き込み
			Encoding enc = new UTF8Encoding();

			// 書き込むファイル( ドキュメントフォルダ )
			string write_path = string.Format($@"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\cs_file_list.txt");

			// 追加書き込み( false で上書き )
			try
			{
				using (StreamWriter write_file = new StreamWriter(write_path, false, enc))
				{
					// 書き込み
					write_file.Write(file_list.ToString());

					// UTF8N 確認の為
					write_file.WriteLine("日本語表示");

					// 閉じる
					write_file.Close();
				}

			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Message);
			}
			// **********************************************
			// try ブロックは
			// 編集メニュー > IntelliSense > ブロックの挿入
			// **********************************************

			Console.ReadLine();
		}
	}
}


🔻 テキストエディタのタブを保持する設定


※ 変換は全てコピー > 削除 > 貼り付け


Google 翻訳ブックマークレット

テキストを選択してブックマークレットを実行すると、その部分だけを翻訳し、なにも選択せずにただブックマークレットを実行するとそのページ全体を翻訳します
🔻 以下のリンクをブックマークバーにドロップしてください
Google英→日

Google日→英

Edge の場合は一旦何かのお気に入りを作成してから、上記リンクのコピーを編集で URL に対して置き換える必要があります
🔻 このページの英語翻訳 🔻 Google英→日 のソースコード
javascript: (function() {
	var b = ((window.getSelection && window.getSelection()) || (document.getSelection && document.getSelection()) || (document.selection && document.selection.createRange && document.selection.createRange().text));
	if (b != '') {
		window.open('https://translate.google.co.jp/?hl=ja&tab=wT#en/ja/' + encodeURIComponent(b));
	} else {
		window.open('https://translate.google.co.jp/translate?sl=en&tl=ja&js=n&prev=_t&hl=ja&ie=UTF-8&u=' + encodeURIComponent(location.href) + '&act=url');
	}
})();

🔻 Google日→英 のソースコード
javascript: (function() {
	var b = ((window.getSelection && window.getSelection()) || (document.getSelection && document.getSelection()) || (document.selection && document.selection.createRange && document.selection.createRange().text));
	if (b != '') {
		window.open('https://translate.google.co.jp/?hl=ja&tab=wT#ja/en/' + encodeURIComponent(b));
	} else {
		window.open('https://translate.google.co.jp/translate?sl=ja&tl=en&js=n&prev=_t&hl=ja&ie=UTF-8&u=' + encodeURIComponent(location.href) + '&act=url');
	}
})();




XCOPY で新しいファイルのみバックアップする為のスクリプトを作成するスクリプト / VBScript

⭕ ディレクトリ選択でバックアップするフォルダを決定 ⭕ カレント(このスクリプトを実行したフォルダ)にスクリプトが作成されます ⭕ 新しいスクリプトを実行 ⭕ カレントにバックアップ用のフォルダが作成されます ⭕ バックアップするフォルダ内をそのフォルダ内に全てコピーします ▼ 実行時に表示されるフォルダ選択 XCOPY なので、2回目以降は新しいファイルのみコピーします ▼ 作成されたスクリプトのサンプルです
strName = "BK_C_temp_lightbox"
strTarget = "C:\temp\lightbox"
strBackupFolder = "C:\tmp\vbs"
if MsgBox( strTarget & vbCrLf & "のバックアップを開始します。よろしいですか? (保存先:" & strBackupFolder & "\" & strName & ")", 1 ) = 2 then
	Wscript.Quit
end if
Set WshShell = Wscript.CreateObject( "WScript.Shell" )
ExecCommand = "cmd.exe /C ""xcopy.exe """ & strTarget & """ """ & strBackupFolder & "\" & strName & "\"" /D /E /C /S /Y & PAUSE"""
Call WshShell.Run( ExecCommand )


▼ 使用するオプション
/D : コピー元の日付がコピー先の日付より新しいファイルだけをコピーします
/E : ディレクトリまたはサブディレクトリが空であってもコピーします
/C : エラーが発生してもコピーを続けます
/S : 空の場合を除いて、ディレクトリとサブディレクトリをコピーします
/Y : 既存のファイルを上書きする前に確認のメッセージを表示しません
一番重要なのは、/D です。/S /E で、存在するディリクトリはすべてコピーされます。/E /Y によって、最後まで停止する事なく実行されます。 追加で使う事が想定されるオプション コピーしたくないディレクトリやファイルがある場合、以下のように指定します。 /EXCLUDE:ファイルのパス ファイルのパスが示すテキストファイル内に、除外するディレクトリやファイルにある文字列の一部を1 行に 1 つずつ記述します。 その文字列が、コピー対象ファイルの絶対パスの一部と一致した場合、そのファイルはコピーから除外されます。 ▼ 例 ⭕ "\obj\" という文字列を指定するとディレクトリ obj の下の全ファイルが除外 されます。 ⭕ ".obj" という文字列を指定すると .obj という拡張子のファイルがすべて除外されます ソースコード
' ***********************************************************
' 処理開始
' ***********************************************************
Set Fso = Wscript.CreateObject( "Scripting.FileSystemObject" )
Set Shell = Wscript.CreateObject( "Shell.Application" )

' ***********************************************************
' 実行中ディレクトリの取得
' ***********************************************************
strPath = Wscript.ScriptFullName 
Set objFile = Fso.GetFile( strPath )
strBackupFolder = Fso.GetParentFolderName( objFile )

' ***********************************************************
' バックアップ対象ディレクトリの取得
' ***********************************************************
' ① 省略すると、ルートはデスクトップ
Set objFolder = Shell.BrowseForFolder( 0, "バックアップするフォルダを選択してください", &H4B )

' ② 文字列による直接指定
' strRoot = "c:\"
' Set objFolder = Shell.BrowseForFolder( 0, "バックアップするフォルダを選択してください", &H4B, strRoot )

' ③ ルートを番号で指定( この場合は C:\Users\username\AppData\Local )
' ※ あまり現実的ではない特殊ディレクトリの選択
' nRoot = &h1c
' Set objFolder = Shell.BrowseForFolder( 0, "バックアップするフォルダを選択してください", &H4B, nRoot )

if objFolder is nothing then
	WScript.Quit
end if
if not objFolder.Self.IsFileSystem then
	WScript.Echo "ファイルシステムではありません"
	WScript.Quit
end if

strTargetFolder = objFolder.Self.Path
strName = Replace( strTargetFolder, ":", "" )
strName = Replace( strName, "\", "_" )
strName = Replace( strName, " ", "" )
strName = "BK_" & strName

' ***********************************************************
' スクリプト作成
' ***********************************************************
Set OutFile = Fso.OpenTextFile( strBackupFolder & "\" & strName & ".vbs", 2, True )

OutFile.WriteLine "strName = """ & strName & """"
OutFile.WriteLine "strTarget = """ & strTargetFolder & """"
OutFile.WriteLine "strBackupFolder = """ & strBackupFolder & """"
OutFile.Write "if MsgBox( strTarget & vbCrLf & ""のバックアップを開始します。よろしいですか? (保存先:"" & strBackupFolder & ""\"" & strName & "")"""
OutFile.WriteLine ", 1 ) = 2 then"
OutFile.WriteLine "	Wscript.Quit"
OutFile.WriteLine "end if"

OutFile.WriteLine "Set WshShell = Wscript.CreateObject( ""WScript.Shell"" )"
OutFile.Write "ExecCommand = ""cmd.exe /C """"xcopy.exe """""" & strTarget & """""" """""" & strBackupFolder & ""\"" & strName & ""\"""""
OutFile.WriteLine " /D /E /C /S /Y & PAUSE"""""""
OutFile.WriteLine "Call WshShell.Run( ExecCommand )"

OutFile.Close

WScript.Echo "バックアップスクリプト : " &  strName & ".vbs" & " を作成しました"


' ***********************************************************
' ディレクトリ指定用番号
' https://docs.microsoft.com/ja-jp/windows/desktop/api/shldisp/ne-shldisp-shellspecialfolderconstants
' typedef enum {
' 	ssfALTSTARTUP = 0x1d,
' 	ssfAPPDATA = 0x1a,
' 	ssfBITBUCKET = 0x0a,
' 	ssfCOMMONALTSTARTUP = 0x1e,
' 	ssfCOMMONAPPDATA = 0x23,
' 	ssfCOMMONDESKTOPDIR = 0x19,
' 	ssfCOMMONFAVORITES = 0x1f,
' 	ssfCOMMONPROGRAMS = 0x17,
' 	ssfCOMMONSTARTMENU = 0x16,
' 	ssfCOMMONSTARTUP = 0x18,
' 	ssfCONTROLS = 0x03,
' 	ssfCOOKIES = 0x21,
' 	ssfDESKTOP = 0x00,
' 	ssfDESKTOPDIRECTORY = 0x10,
' 	ssfDRIVES = 0x11,
' 	ssfFAVORITES = 0x06,
' 	ssfFONTS = 0x14,
' 	ssfHISTORY = 0x22,
' 	ssfINTERNETCACHE = 0x20,
' 	ssfLOCALAPPDATA = 0x1c,
' 	ssfMYPICTURES = 0x27,
' 	ssfNETHOOD = 0x13,
' 	ssfNETWORK = 0x12,
' 	ssfPERSONAL = 0x05,
' 	ssfPRINTERS = 0x04,
' 	ssfPRINTHOOD = 0x1b,
' 	ssfPROFILE = 0x28,
' 	ssfPROGRAMFILES = 0x26,
' 	ssfPROGRAMFILESx86 = 0x30,
' 	ssfPROGRAMS = 0x02,
' 	ssfRECENT = 0x08,
' 	ssfSENDTO = 0x09,
' 	ssfSTARTMENU = 0x0b,
' 	ssfSTARTUP = 0x07,
' 	ssfSYSTEM = 0x25,
' 	ssfSYSTEMx86 = 0x29,
' 	ssfTEMPLATES = 0x15,
' 	ssfWINDOWS = 0x24
' } ShellSpecialFolderConstants;
' ***********************************************************




関連する Microsoft ドキュメント

Shell Reference
Shell Objects for Scripting and Microsoft Visual Basic
Shell object
Shell.BrowseForFolder method



古いけれどとても使いやすい TeraPad の導入と簡単な初期設定

2019年3月 時点で 最新版は、1.09 です。1.08リリースから約8年以上経過しており、古いソフトではありますが初心者向きかつプログラミングにも使えるとても良いテキストエディタです。

プロとしての作業内容では、直接表現できない文字があります。その場合は最新のテキストエディタが必要です。

※ インストーラは使う必要の無いソフトなので、zip 版を前提に話を進めて行きます

インストール場所を決める

どこでも良いですが、他のフリーソフトを運用する事も考えて C ドライブに tools というフォルダを作成して、その中に tpad109.zip を置いて解凍しましょう。ここでは TeraPad.exe が tpad109 というフォルダ内に置かれた状態であるとします。

オプション設定

起動後、まずオプションダイアログを開きます。




ウインドウ

最初にまず、『ウインドウ』タブを開いて以下のように設定します

1) 何より、以前のウインドウ位置やサイズは復帰してもらわないと非常に不便です。
2) 現在開いているファイルがどこにあるかをすぐ知る為に、タイトルバーの設定は必須です。




表示

タブや空白文字が非表示になっているので、必ず表示するようにしておきます。特にソースコードを扱う上において、漢字スペースかどうかの判断は一目瞭然にしておく必要があります。




ファイル

これは必ずしも必要ではありませんが、アプリケーション作成やログのチェック等の作業で、リアルタイムに結果をエディタで見る必要がある事のほうが多いので、設定しておくといいと思います。




SendTo フォルダにショートカットを作成する

エクスプローラのアドレスに sendto と入力すると、SendTo フォルダへ移動できます
送るのメニューの先頭にする為に _Tarpad とショートカットの名前に _ を付けています

SendTo フォルダにショートカットを作成しておくと、右クリックからどんなファイルも対象にして開く事ができます。ショートカットはいったんデスクトップに作成しておいて、後で以下のフォルダに移動するといいと思います

C:\Users\ユーザー\AppData\Roaming\Microsoft\Windows\SendTo



簡単に SendTo フォルダを開くスクリプトは以下のようになります。

▼ SendToフォルダを開くスクリプト
Set obj = CreateObject("Shell.Application")
Set objFolder = obj.NameSpace( &h09 )
obj.Explore(objFolder.Self.Path)
Set obj = Nothing




PHP による超簡易掲示板 ( JSONでデータを保存します ) / CSS でレスポンシブ対応

▼ ノーマル

▼ スマホ




保存データを行単位で区切り文字で分けて投稿データを保存する方法は古くからありますが、JSON 形式で保存しておくと、投稿データ内の改行やクォートなどのデータを自分で処理する必要がなくなる上に、新しい項目も追加するのが容易になります。さらに、データが JSON で作られるので、そのまま http で他のアプリケーションからアクセスする事も容易になります

一応、MVC にのっとり、M(model.php) / V(view.php) / C(board.php) になっています

board.php

error_reporting(E_ALL & ~E_NOTICE); は、$_POST 等の変数の参照時に未定義(ブラウザから送られていない)時にでも、空文字列が入っているとみなして処理できるようにするものです。逆に、全てのエラーを出力するようにした場合、代入されていな い値を使用した場合は、警告を発生します( 必要であれば、php.ini で設定します )

<?php
error_reporting(E_ALL & ~E_NOTICE);
// **************************************
// php.ini の output_buffering をチェックして
// 有効になっていた場合は、header の前に出力可能です
// **************************************

// **************************************
// 通常の HTML として出力します
// **************************************
header( "Content-Type: text/html; charset=utf-8" );

// **************************************
// キャッシュを無効にするヘッダ
// ※ いろいろあるのは念のため
// **************************************
header( "Expires: Thu, 19 Nov 1981 08:52:00 GMT" );
header( "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0" );
header( "Pragma: no-cache" );

// **************************************
// 関数の定義を読み込みます
// **************************************
require_once("model.php");

// **************************************
// $_POST['send'] != "" は送信ボタンが
// クリックされた事を示します
// さらに、テキストエリアに何か入力され
// た場合に処理を行います
// **************************************
$_POST['text'] = preg_replace( "/^[ \s]+/u", "", $_POST['text'] );
$_POST['text'] = preg_replace( "/[ \s]+$/u", "", $_POST['text'] );
if ( $_POST['send'] != "" && $_POST['text'] != "" ) {

	// データの書き込み処理
	post_data();

}

// データの表示処理
disp_data();


// **************************************
// ▼ 以下は画面です。$log_text を
//    埋め込んでいます
// **************************************
require_once("view.php");
?>

キャッシュ無効は、先頭に 
session_cache_limiter('nocache');
session_start();
でもいいと思います


FORM は一般的な POST メソッドで送信されます。なので、書き込んだ直後にリダイレクトして GET メソッドで呼び出しなおすという処理が入っています。タイトルの『超簡易掲示板 ( JSON )』をクリックすると、GET メソッドでの呼び出しであるリンクとなっています。

投稿データの表示内容は、いったん文字列で作成して後から view.php の該当部分に埋め込む形式です。最新のデータは、array_unshift によって、データの先頭に追加されます。

HTML 要素を無効にする方法としては、htmlentitieshtmlspecialchars がありますが、初心者向けとして最低限の置き換えを str_replace で実装しています。

json_encode による、オブジェクトから文字列の変換では、オプションの JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT でデバッグしやすいように可読性に重点を置いています。

model.php
<?php

// **************************************
// データの書き込み処理
// **************************************
function post_data() {

	// データを一括読み込み
	$log_text = @file_get_contents("board.log");

	$json = json_decode( $log_text );
	// 空のファイルかまたは、JSON データでは無い場合
	if ( $json === null ) {

		// JSON 用クラス作成
		$json = new stdClass;
		// 行データを格納する配列を作成
		$json->item = array();

	}

	// 改行コードを \n のみ(1バイト)にする
	$_POST['text'] = str_replace("\r","",$_POST['text']);

	// HTML 要素を無効にする
	$_POST['text'] = str_replace("<","&lt;",$_POST['text']);
	$_POST['text'] = str_replace(">","&gt;",$_POST['text']);

	// HTML 要素を無効にする
	$_POST['subject'] = str_replace("<","&lt;",$_POST['subject']);
	$_POST['subject'] = str_replace(">","&gt;",$_POST['subject']);
	$_POST['name'] = str_replace("<","&lt;",$_POST['name']);
	$_POST['name'] = str_replace(">","&gt;",$_POST['name']);

	// 新しい投稿用のクラス作成
	$board_data = new stdClass;

	// text プロパティに 入力された本文をセット
	$board_data->text = $_POST['text'];
	// subject プロパティに 入力されたタイトルをセット
	$board_data->subject = $_POST['subject'];
	// name プロパティに 入力された名前をセット
	$board_data->name = $_POST['name'];
	// subject プロパティに 入力されたタイトルをセット
	$board_data->datetime = $_POST['datetime'];

	// 配列の先頭に 新しい投稿データをセット
	array_unshift($json->item, $board_data);

	// 全ての投稿データを JSON として一括書き込み
	file_put_contents("./board.log", json_encode( $json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT ) );

	// GET メソッドで再表示します
	header( "Location: {$_SERVER["PHP_SELF"]}" );

	exit();


}

// **************************************
// データの表示処理
// **************************************
function disp_data() {

	// 埋め込み用データを global 宣言
	global $log_text;

	// データを一括読み込み
	$log_text = @file_get_contents("./board.log");
	// ファイルが存在しない場合
	if ( $log_text === false ) {
		$log_text = "ここに投稿データが表示されます";
		return;
	}

	$json = json_decode( $log_text );
	// 空のファイルかまたは、JSON データでは無い
	if ( $json === null ) {
		$log_text = "ここに投稿データが表示されます";
		return;
	}

	// 表示用の埋め込みに使用される文字列変数
	$log_text = "";
	foreach( $json->item as $v ) {
	
		// **************************************
		// 本文の改行は br 要素で表現します
		// **************************************
		$v->text = str_replace("\n", "<br>\n", $v->text );

		// **************************************
		// 記事の境界を hr 要素で表現します
		// **************************************
		$v->text .= "<hr>\n";

		// **************************************
		// 行毎に表示 HTML を作成
		// **************************************
		$log_text .= "<div class='title'>【{$v->subject}】( {$v->name} : {$v->datetime} ) </div>" . $v->text;
	
	}


}

?>


投稿時の日付データは、ブラウザ側でセットするようにしています。特に日付に関しては JavaScript ではスマートな方法が無いので、学習のきっかけ用としてこのようになっています。また、送信時のイベント処理としても重要なサンプルとなり、jQuery の基本サンプルでもあります。

※ jQuery は、Google のホスティングを使用しています。

view.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<style>
* {
	font-family: "ヒラギノ角ゴPro W3","Hiragino Kaku Gothic Pro","メイリオ",Meiryo,"MS Pゴシック",Verdana,Arial,Helvetica,sans-serif;
}

textarea {
	height: 100px;
}

@media screen and ( min-width:480px ) {
	input {
		width: 400px;
	}
	textarea {
		width: 500px;
	}
}

@media screen and ( max-width:479px ) {

	input,textarea {
		width:100%;
	}

}

.title {
	border: 1px solid #aaa;
	padding: 4px;
	margin-bottom: 6px;
}

</style>

<script>

$( function(){

	// フォーム送信イベント
	$("form").on("submit", function(){

		// 日付文字列をクライアントで作成して送信
		var dateNow = new Date();
		var dateString = 
			dateNow.getFullYear() + "/" + 
			("0"+(dateNow.getMonth()+1)).slice(-2)+ "/" + 
			("0"+(dateNow.getDate())).slice(-2);
		var timeString = 
			("0"+(dateNow.getHours())).slice(-2) + ":" + 
			("0"+(dateNow.getMinutes())).slice(-2) + ":" + 
			("0"+(dateNow.getSeconds())).slice(-2);

		// hidden フィールドにセット
		$("#datetime").val( dateString + " " + timeString );

	});
});

</script>
</head>

<body>
<h3><a href="board.php" style="color:black;">超簡易掲示板 ( JSON )</a></h3>

<form method="POST">
	<div>タイトル <input type="text" name="subject"></div>
	<div>名  前 <input type="text" name="name"></div>
	<div><textarea name="text"></textarea>
	<input type="hidden" name="datetime" id="datetime"></div>
	<div><input type="submit" name="send" value="送信"></div>
</form>
<br>

<?= $log_text ?>

</body>
</html>


JSON は、item プロパティが配列になり、複数項目の投稿データが格納されます。

JSON データ
{
    "item": [
        {
            "text": "最低限の機能を持った掲示板です。\nデータ形式は JSON でとても拡張しやすく便利です。",
            "subject": "こんにちは",
            "name": "山田 タロウ",
            "datetime": "2019\/02\/22 13:48:00"
        }
    ]
}




VBScript : Excel のブックを新規に作成する( .xlsx と .xls を選択 )

最新の Excel では新規で自動的に作成されるシートのデフォルトは一つです。但しそれは Excel のオプション設定で変更可能なので、必要であれば Book.Worksheets.Count というように現在のシート数を取得してコードを変更すれば良いと思います。

保存する形式としては、可能列挙型 (Excel) / SaveAs メソッド で使用する定数 より選択して SaveAs メソッドの第二引数に指定します。ここでは、.xls( 56 ) を使用しています
' ****************************
' Excel オブジェクト作成
' ****************************
Set App = CreateObject("Excel.Application")

' ****************************
' 警告を出さないようにする
' ****************************
App.DisplayAlerts = False

' ****************************
' ブック追加
' ****************************
App.Workbooks.Add()

' ****************************
' 追加したブックを取得
' ****************************
Set Book = App.Workbooks( App.Workbooks.Count )

' ****************************
' 現状、ブックにはシート一つ
' という前提で処理していますが
' 必要であれば、Book.Worksheets.Count
' で現在のシートの数を取得できます
' ****************************
Set Worksheet = Book.Worksheets( 1 )
Worksheet.Activate()

' ****************************
' Add では 第二引数に指定した
' オブジェクトのシートの直後に、
' 新しいシートを追加します。
' ****************************
Call Book.Worksheets.Add(,Worksheet)

' ****************************
' シート名設定
' ****************************
Book.Sheets(1).Name = "新しい情報"
Book.Sheets(2).Name = "予備情報"

' ****************************
' 参照
' 最後の 1 は、使用するフィルター
' の番号です
' ****************************
FilePath = App.GetSaveAsFilename(,"Excel ファイル (*.xlsx), *.xlsx,古いExcel ファイル (*.xls), *.xls", 1)
if FilePath = "False" Then
	MsgBox "Excel ファイルの保存選択がキャンセルされました"
	Wscript.Quit()
End If

' ****************************
' 保存
' 拡張子を .xls で保存するには
' Call ExcelBook.SaveAs( BookPath, 56 ) とします
' ****************************
on error resume next
if Ucase(Right(FilePath,3)) = "XLS" then
	Call Book.SaveAs( FilePath, 56 )
else
	Book.SaveAs( FilePath )
end if
if Err.Number <> 0 then
	MsgBox( "ERROR : " & Err.Description )
end if
on error goto 0

' ****************************
' Excel をアプリケーションとして終了
' ****************************
App.Quit()

' ****************************
' Excel を VBScript から開放
' ****************************
Set App = Nothing

' ****************************
' オブジェクト変数を初期化
' ( 初期化しないとオブジェクト扱いされる )
' ****************************
App = Empty


MsgBox( "処理が終了しました" )


Microsoft ドキュメント

Application.GetSaveAsFilename メソッド (Excel)

Application.GetOpenFilename メソッド (Excel)

Worksheets.Add メソッド (Excel)

Workbook.SaveAs メソッド (Excel)

可能列挙型 (Excel) / SaveAs メソッド で使用する定数