山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他インターネットよりファイルを1行ずつ読み出しUTF8文字列をUNICODE又はSJISに変換してファイルへ保存する
概要
指定したURLのファイルをインターネットから1行ずつ取得しUTF8文字列をUNICODEでコンパイルした場合はUNICODE、マルチバイトでコンパイルした場合はSJISに変換してファイルに保存します。
本プログラムの使用方法はコマンドプロンプトを実行し、以下のように入力します。
以下の場合、私のホームページのUTF8文字列を含むutf8.htmlをファイルtest.htmlに保存します。
WININETは1行ずつの読み込みに対応していないので、バッファリングと1行読み込みをサポートしたクラスを作成しています。
本プログラムの使用方法はコマンドプロンプトを実行し、以下のように入力します。
以下の場合、私のホームページのUTF8文字列を含むutf8.htmlをファイルtest.htmlに保存します。
wgetutf8 http://yamatyuu.net/computer/html/charset/utf8.html test.htmlインターネットからの読み込みにはWININETを使用しています。
WININETは1行ずつの読み込みに対応していないので、バッファリングと1行読み込みをサポートしたクラスを作成しています。
テスト環境
コンパイラ
Visual C++ 2008 Standard 32/64bitVisual C++ 2013 Express 32/64bit
プロジェクトの作成
Win32プロジェクト Windowsコンソールアプリケーション実行環境
Windows 8.1 Enterprise 64bitWindows 7 EnterPrise Service Pack 1 64bit
Windows Vista Ultimate Service Pack 2 32bit
Windows XP Professional Service Pack 3 32bit
プログラムソースの概要
_tmain
UNICODE文字を標準エラー出力に正しく表示させるために_tsetlocale関数によりロケールを設定します。 InternetOpen APIによりインタネットハンドルを取得します。APIが0を返した場合は、インタネットハンドルを取得できなかったので 標準エラー出力にエラーメッセージを表示しプログラムを終了させます。
_tfopen_sにより取得したデータを保存するためのファイルを書き込みでバイナリモードで開きファイルハンドルを取得します。
ファイルが開けなかった場合は、InternetCloseHandle APIによりインターネットハンドルを閉じて 標準エラー出力にエラーメッセージを表示しプログラムを終了させます。
webUTF8TextGet関数によりインタネット上のファイルを読み取り、ファイルに保存します。
InternetCloseHandle APIによりインターネットハンドルを閉じます。
fclose関数によりファイルハンドルを閉じます。
webUTF8TextGet
行単位での入力が可能なようにINETクラスを作成し、メンバー関数openで指定URLをオープンしハンドルを取得します。オープンできなかった場合は、関数を終了します。
INETクラスgetsメンバー関数で1行を取得します。
MultiByteToWideChar APIによりUTF8文字列をUNICODE文字列に変換します。
マルチバイトでコンパイルされている場合は、WideCharToMultiByte APIによりUNICODE文字列をSJIS文字列に変換します。
_ftprintf関数でファイルに書き込みます。
読み込める行がなくなるまで、繰り返します。
INETクラス
inet.hで定義されています。WININETは行単位の入力をサポートしていないので、クラス内でバッファリングを行い、 getsメンバー関数により行単位を要求された場合、バッファ内の行部分をコピーして返します。バッファが空になったらバッファサイズ分読み込みを行います。
¥nか¥rが行末であると解釈して処理を行います。
プログラムソース
wgetutf8.cpp
// インターネットより指定したurlを読み出しUTF8文字をUNICODE又はSJISに変換して指定したファイルへ保存します。
// Visual C++ 2008/2013 Unicode/マルチバイト
#include <windows.h>
#include <stdio.h>
#include <wininet.h>
#include <tchar.h>
#include <locale.h>
#include "inet.h"
#pragma comment(lib,"wininet.lib")
// 指定したURLのUTF8テキストをUNICODEまたはSJISに変換して指定ファイルに保存する
void webUTF8TextGet(HINTERNET hInet, TCHAR* url, FILE* fp);
int _tmain(int argc,TCHAR** argv){
HINTERNET hInet;
_tsetlocale(LC_ALL, _TEXT(""));
if (argc != 3){
_tprintf(_TEXT("使用方法\nwgetutf8 [url] [保存ファイル名]\n"));
return 1;
}
//インターネット(WinInet)開始
hInet = InternetOpen(TEXT("wxz123"),
INTERNET_OPEN_TYPE_PRECONFIG,
NULL, NULL, 0);
if (hInet == NULL) {
perror("オープンエラー\n");
return 2;
}
FILE* fp;
#ifdef _UNICODE
_tfopen_s(&fp, argv[2], _TEXT("w,ccs=UNICODE"));
#else
_tfopen_s(&fp, argv[2], _TEXT("w"));
#endif
webUTF8TextGet(hInet,argv[1],fp);
fclose(fp);
InternetCloseHandle(hInet);
return 0;
}
// 指定したURLのUTF8テキストをUNICODEまたはSJISに変換して指定ファイルに保存する
void webUTF8TextGet(HINTERNET hInet, TCHAR* url, FILE* fp){
HINTERNET h;
INET inet(hInet);
h = inet.open(url);
char src[1024];
TCHAR* dtc;
while (inet.gets(src, sizeof(src))){
WCHAR utf16[1024];
// UTF8をUNICODEに変換
MultiByteToWideChar(CP_UTF8, 0, src, -1, utf16, sizeof(utf16) / sizeof(TCHAR));
#ifdef _UNICODE
dtc = utf16;
#else
char sjis[1024];
// UNICODEをSJISに変換
WideCharToMultiByte(932, 0, utf16, -1, sjis, sizeof(sjis), NULL, NULL);
dtc = sjis;
#endif
_ftprintf(fp, _TEXT("%s\n"), dtc);
}
return;
}
inet.h
#ifndef INET_H
// インターネットから1行ずつ読み取るクラス
#define INET_H 0x3000
#define INET_BUF_SIZE_DEF 65536
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <wininet.h>
#include <assert.h>
#include <TCHAR.H>
class INET{
HINTERNET hInet;
HINTERNET hUrl;
char* buf; // 読み取りバッファ(文字コード変換なし)
unsigned p; // バッファ内の位置
DWORD len; // バッファの有効データー数
int wpos;
int n; // バッファ内の読み出し可能先頭位置
int INET_BUF_SIZE;
bool new_mem_f;
public:
UINT64 total_read;
void init(HINTERNET h,void* bp,int sz){
hInet=h;
hUrl=0;
p=len=0;
INET_BUF_SIZE=sz;
buf=(char*)bp;
new_mem_f=false;
}
INET(){
hInet=0;
hUrl=0;
p=len=0;
INET_BUF_SIZE=0;
buf=0;
new_mem_f=false;
total_read=0;
}
INET(HINTERNET h){
hInet=h;
hUrl=0;
p=len=0;
INET_BUF_SIZE=INET_BUF_SIZE_DEF;
buf=new char[INET_BUF_SIZE+1];
new_mem_f=true;
}
INET(HINTERNET h,int sz){
hInet=h;
hUrl=0;
p=len=0;
INET_BUF_SIZE=sz;
buf=new char[INET_BUF_SIZE];
new_mem_f=true;
}
HINTERNET open(TCHAR* url){
wpos=0;
n=0;
return hUrl=InternetOpenUrl(hInet, url, NULL, 0, INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, 0);
}
int read(char* buf,int max){
int len;
InternetReadFile(hUrl, buf, max - 1, (LPDWORD)&len);
total_read += len;
return len;
}
char* gets(char* b,int max){ // 1行分取得 改行コードを除去する
int i=0;
for(;;){
if(p==0 || len==0){ // バッファ内に有効データーがないのでサイトから読み取る
len=read(buf,INET_BUF_SIZE);
}
if(len==0){
return 0;
}
for(;p<len;p++){
if(i==max-1){
b[i]='\0';
return b;
}
if(buf[p]=='\n' || buf[p]=='\r'){
b[i]='\0';
++p;
return b;
}else{
b[i++]=buf[p];
}
}
p=0;
}
}
void close(void){
if(hUrl)
InternetCloseHandle(hUrl);
hUrl=0;
}
~INET(){
if(hUrl)
InternetCloseHandle(hUrl);
if(new_mem_f==true && buf)
delete buf;
INET_BUF_SIZE=0;
}
};
#endif
ソースファイルと実行ファイルのダウンロード
Copyright (C) 2012 山本ワールド All Rights Reserved.