スキップしてメイン コンテンツに移動

C#: How to Read Image MetaData from System.Drawing.Imaging.PropertyItem

I have written simple debug code for printing out PropertyItems in System.Drawing.Image object.
The key part of the code:

  • mapping between Id property of PropertyItem and description of associated to the property item.
  • decode PropertyItem value (byte array) to human readable format string

The code itself will be shown at the bottom of this post.
Below is a sample image which will be passed to the program and the corresponding output generated by the program.
Property Item 1
   Id: 0x10e
   Type: 2
   Length: 17 bytes
   Type String: ASCII
   Descriotion: PropertyTagImageDescription
   Value      : MetaData Example
Property Item 2
   Id: 0x131
   Type: 2
   Length: 7 bytes
   Type String: ASCII
   Descriotion: PropertyTagSoftwareUsed
   Value      : Picasa
Property Item 3
   Id: 0x9000
   Type: 7
   Length: 4 bytes
   Type String: Undefined
   Descriotion: PropertyTagExifVer
   Value      : 
Property Item 4
   Id: 0xa002
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagExifPixXDim
   Value      : 1440
Property Item 5
   Id: 0xa003
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagExifPixYDim
   Value      : 1440
Property Item 6
   Id: 0xa420
   Type: 2
   Length: 33 bytes
   Type String: ASCII
   Descriotion: Unknown
   Value      : 199e785efd74401dff564baa559c2f25
Property Item 7
   Id: 0x9c9b
   Type: 1
   Length: 34 bytes
   Type String: Array of bytes
   Descriotion: Unknown
   Value      : 77,0,101,0,116,0,97,0,68,0,97,0,116,0,97,0,32,0,69,0,120,0,97,0,109,0,112,0,108,0,101,0,0,0
Property Item 8
   Id: 0x9c9c
   Type: 1
   Length: 28 bytes
   Type String: Array of bytes
   Descriotion: Unknown
   Value      : 84,0,101,0,115,0,116,0,32,0,67,0,111,0,109,0,109,0,101,0,110,0,116,0,115,0,0,0
Property Item 9
   Id: 0x501b
   Type: 1
   Length: 6780 bytes
   Type String: Array of bytes
   Descriotion: PropertyTagThumbnailData
   Value      : 255,216,255,219,0,67,0,8,6,6,7,6,5,8,7,7,7,9,9,8,10,12,20,13,12,11,11,12,25,18,19,15,20,29,26,31,30,...
Property Item 10
   Id: 0x5023
   Type: 3
   Length: 2 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagThumbnailCompression
   Value      : 6
Property Item 11
   Id: 0x502d
   Type: 5
   Length: 8 bytes
   Type String: Rational
   Descriotion: PropertyTagThumbnailResolutionX
   Value      : 72,1
Property Item 12
   Id: 0x502e
   Type: 5
   Length: 8 bytes
   Type String: Rational
   Descriotion: PropertyTagThumbnailResolutionY
   Value      : 72,1
Property Item 13
   Id: 0x5030
   Type: 3
   Length: 2 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagThumbnailResolutionUnit
   Value      : 2
Property Item 14
   Id: 0x201
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagJPEGInterFormat
   Value      : 4488
Property Item 15
   Id: 0x202
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagJPEGInterLength
   Value      : 6780
Property Item 16
   Id: 0x5091
   Type: 3
   Length: 128 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagChrominanceTable
   Value      : 5,5,7,14,30,30,30,30,5,6,8,20,30,30,30,30,7,8,17,30,30,30,30,30,14,20,30,30,30,30,30,30,30,30,30,30,...
Property Item 17
   Id: 0x5090
   Type: 3
   Length: 128 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagLuminanceTableThe thread 'vshost.RunParkingWindow' (0x8a0) has exited with code 0 (0x0).
   Value      : 5,3,3,5,7,12,15,18,4,4,4,6,8,17,18,17,4,4,5,7,12,17,21,17,4,5,7,9,15,26,24,19,5,7,11,17,20,33,31,23,...

Code for Printing Out PropertyItem

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;

namespace Utility
{
    public static class ImagePropertyUtils
    {

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/xddt0dz7%28v=vs.110%29.aspx
        /// </summary>
        public static void PrintProperties(this Image image)
        {
            // Get the PropertyItems property from image.
            var propItems = image.PropertyItems;

            // For each PropertyItem in the array, display the ID, type, and length.
            int count = 0;
            foreach (var propItem in propItems)
            {
                count++;
                // raw data
                Console.WriteLine("Property Item " + count.ToString());
                Console.WriteLine("   Id: 0x" + propItem.Id.ToString("x"));
                Console.WriteLine("   Type: " + propItem.Type.ToString());
                Console.WriteLine("   Length: " + propItem.Len.ToString() + " bytes");

                // human readable string
                Console.WriteLine("   Type String: " + PropItemToTypeString[propItem.Type]);
                Console.WriteLine("   Descriotion: " + (PropItemIdToDescriotionString.ContainsKey(propItem.Id) ? PropItemIdToDescriotionString[propItem.Id]: "Unknown"));
                Console.WriteLine("   Value      : " + propItem.ReadPropertValueAsString().Trim(100));
            }
        }

        const int BYTES = 1;
        const int ASCII = 2;
        const int SHORT = 3;
        const int LONG = 4;
        const int RATIONAL = 5;
        const int SLONG = 9;
        const int SRATIONAL = 10;

        /// <summary>
        /// According to http://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.type(v=vs.110).aspx
        /// </summary>
        private readonly static Dictionary<int, string> PropItemToTypeString = new Dictionary<int, string>()
        {
            {BYTES,     "Array of bytes"},
            {ASCII,     "ASCII"},
            {SHORT,     "Short (16 bit int)"},
            {LONG,      "Long (32 bit int)"},
            {RATIONAL,  "Rational"},
            {6,         "Not Used"},
            {7,         "Undefined"},
            {8,         "Not Used"},
            {SLONG,     "SLong"},
            {SRATIONAL, "SRational"}
        };

        /// <summary>
        /// According to http://msdn.microsoft.com/de-de/library/ms534416.aspx
        /// </summary>
        private readonly static Dictionary<int, string> PropItemIdToDescriotionString = new Dictionary<int, string>()
        {
            {0x013B, "PropertyTagArtist"},
            {0x0102, "PropertyTagBitsPerSample"},
            {0x0109, "PropertyTagCellHeight"},
            {0x0108, "PropertyTagCellWidth"},
            {0x5091, "PropertyTagChrominanceTable"},
            {0x0140, "PropertyTagColorMap"},
            {0x501A, "PropertyTagColorTransferFunction"},
            {0x0103, "PropertyTagCompression"},
            {0x8298, "PropertyTagCopyright"},
            {0x0132, "PropertyTagDateTime"},
            {0x010D, "PropertyTagDocumentName"},
            {0x0150, "PropertyTagDotRange"},
            {0x010F, "PropertyTagEquipMake"},
            {0x0110, "PropertyTagEquipModel"},
            {0x9202, "PropertyTagExifAperture"},
            {0x9203, "PropertyTagExifBrightness"},
            {0xA302, "PropertyTagExifCfaPattern"},
            {0xA001, "PropertyTagExifColorSpace"},
            {0x9102, "PropertyTagExifCompBPP"},
            {0x9101, "PropertyTagExifCompConfig"},
            {0x9004, "PropertyTagExifDTDigitized"},
            {0x9292, "PropertyTagExifDTDigSS"},
            {0x9003, "PropertyTagExifDTOrig"},
            {0x9291, "PropertyTagExifDTOrigSS"},
            {0x9290, "PropertyTagExifDTSubsec"},
            {0x9204, "PropertyTagExifExposureBias"},
            {0xA215, "PropertyTagExifExposureIndex"},
            {0x8822, "PropertyTagExifExposureProg"},
            {0x829A, "PropertyTagExifExposureTime"},
            {0xA300, "PropertyTagExifFileSource"},
            {0x9209, "PropertyTagExifFlash"},
            {0xA20B, "PropertyTagExifFlashEnergy"},
            {0x829D, "PropertyTagExifFNumber"},
            {0x920A, "PropertyTagExifFocalLength"},
            {0xA210, "PropertyTagExifFocalResUnit"},
            {0xA20E, "PropertyTagExifFocalXRes"},
            {0xA20F, "PropertyTagExifFocalYRes"},
            {0xA000, "PropertyTagExifFPXVer"},
            {0x8769, "PropertyTagExifIFD"},
            {0xA005, "PropertyTagExifInterop"},
            {0x8827, "PropertyTagExifISOSpeed"},
            {0x9208, "PropertyTagExifLightSource"},
            {0x927C, "PropertyTagExifMakerNote"},
            {0x9205, "PropertyTagExifMaxAperture"},
            {0x9207, "PropertyTagExifMeteringMode"},
            {0x8828, "PropertyTagExifOECF"},
            {0xA002, "PropertyTagExifPixXDim"},
            {0xA003, "PropertyTagExifPixYDim"},
            {0xA004, "PropertyTagExifRelatedWav"},
            {0xA301, "PropertyTagExifSceneType"},
            {0xA217, "PropertyTagExifSensingMethod"},
            {0x9201, "PropertyTagExifShutterSpeed"},
            {0xA20C, "PropertyTagExifSpatialFR"},
            {0x8824, "PropertyTagExifSpectralSense"},
            {0x9206, "PropertyTagExifSubjectDist"},
            {0xA214, "PropertyTagExifSubjectLoc"},
            {0x9286, "PropertyTagExifUserComment"},
            {0x9000, "PropertyTagExifVer"},
            {0x0152, "PropertyTagExtraSamples"},
            {0x010A, "PropertyTagFillOrder"},
            {0x5100, "PropertyTagFrameDelay"},
            {0x0121, "PropertyTagFreeByteCounts"},
            {0x0120, "PropertyTagFreeOffset"},
            {0x0301, "PropertyTagGamma"},
            {0x5102, "PropertyTagGlobalPalette"},
            {0x0006, "PropertyTagGpsAltitude"},
            {0x0005, "PropertyTagGpsAltitudeRef"},
            {0x0018, "PropertyTagGpsDestBear"},
            {0x0017, "PropertyTagGpsDestBearRef"},
            {0x001A, "PropertyTagGpsDestDist"},
            {0x0019, "PropertyTagGpsDestDistRef"},
            {0x0014, "PropertyTagGpsDestLat"},
            {0x0013, "PropertyTagGpsDestLatRef"},
            {0x0016, "PropertyTagGpsDestLong"},
            {0x0015, "PropertyTagGpsDestLongRef"},
            {0x000B, "PropertyTagGpsGpsDop"},
            {0x000A, "PropertyTagGpsGpsMeasureMode"},
            {0x0008, "PropertyTagGpsGpsSatellites"},
            {0x0009, "PropertyTagGpsGpsStatus"},
            {0x0007, "PropertyTagGpsGpsTime"},
            {0x8825, "PropertyTagGpsIFD"},
            {0x0011, "PropertyTagGpsImgDir"},
            {0x0010, "PropertyTagGpsImgDirRef"},
            {0x0002, "PropertyTagGpsLatitude"},
            {0x0001, "PropertyTagGpsLatitudeRef"},
            {0x0004, "PropertyTagGpsLongitude"},
            {0x0003, "PropertyTagGpsLongitudeRef"},
            {0x0012, "PropertyTagGpsMapDatum"},
            {0x000D, "PropertyTagGpsSpeed"},
            {0x000C, "PropertyTagGpsSpeedRef"},
            {0x000F, "PropertyTagGpsTrack"},
            {0x000E, "PropertyTagGpsTrackRef"},
            {0x0000, "PropertyTagGpsVer"},
            {0x0123, "PropertyTagGrayResponseCurve"},
            {0x0122, "PropertyTagGrayResponseUnit"},
            {0x5011, "PropertyTagGridSize"},
            {0x500C, "PropertyTagHalftoneDegree"},
            {0x0141, "PropertyTagHalftoneHints"},
            {0x500A, "PropertyTagHalftoneLPI"},
            {0x500B, "PropertyTagHalftoneLPIUnit"},
            {0x500E, "PropertyTagHalftoneMisc"},
            {0x500F, "PropertyTagHalftoneScreen"},
            {0x500D, "PropertyTagHalftoneShape"},
            {0x013C, "PropertyTagHostComputer"},
            {0x8773, "PropertyTagICCProfile"},
            {0x0302, "PropertyTagICCProfileDescriptor"},
            {0x010E, "PropertyTagImageDescription"},
            {0x0101, "PropertyTagImageHeight"},
            {0x0320, "PropertyTagImageTitle"},
            {0x0100, "PropertyTagImageWidth"},
            {0x5103, "PropertyTagIndexBackground"},
            {0x5104, "PropertyTagIndexTransparent"},
            {0x014D, "PropertyTagInkNames"},
            {0x014C, "PropertyTagInkSet"},
            {0x0209, "PropertyTagJPEGACTables"},
            {0x0208, "PropertyTagJPEGDCTables"},
            {0x0201, "PropertyTagJPEGInterFormat"},
            {0x0202, "PropertyTagJPEGInterLength"},
            {0x0205, "PropertyTagJPEGLosslessPredictors"},
            {0x0206, "PropertyTagJPEGPointTransforms"},
            {0x0200, "PropertyTagJPEGProc"},
            {0x0207, "PropertyTagJPEGQTables"},
            {0x5010, "PropertyTagJPEGQuality"},
            {0x0203, "PropertyTagJPEGRestartInterval"},
            {0x5101, "PropertyTagLoopCount"},
            {0x5090, "PropertyTagLuminanceTable"},
            {0x0119, "PropertyTagMaxSampleValue"},
            {0x0118, "PropertyTagMinSampleValue"},
            {0x00FE, "PropertyTagNewSubfileType"},
            {0x014E, "PropertyTagNumberOfInks"},
            {0x0112, "PropertyTagOrientation"},
            {0x011D, "PropertyTagPageName"},
            {0x0129, "PropertyTagPageNumber"},
            {0x5113, "PropertyTagPaletteHistogram"},
            {0x0106, "PropertyTagPhotometricInterp"},
            {0x5111, "PropertyTagPixelPerUnitX"},
            {0x5112, "PropertyTagPixelPerUnitY"},
            {0x5110, "PropertyTagPixelUnit"},
            {0x011C, "PropertyTagPlanarConfig"},
            {0x013D, "PropertyTagPredictor"},
            {0x013F, "PropertyTagPrimaryChromaticities"},
            {0x5005, "PropertyTagPrintFlags"},
            {0x5008, "PropertyTagPrintFlagsBleedWidth"},
            {0x5009, "PropertyTagPrintFlagsBleedWidthScale"},
            {0x5007, "PropertyTagPrintFlagsCrop"},
            {0x5006, "PropertyTagPrintFlagsVersion"},
            {0x0214, "PropertyTagREFBlackWhite"},
            {0x0128, "PropertyTagResolutionUnit"},
            {0x5003, "PropertyTagResolutionXLengthUnit"},
            {0x5001, "PropertyTagResolutionXUnit"},
            {0x5004, "PropertyTagResolutionYLengthUnit"},
            {0x5002, "PropertyTagResolutionYUnit"},
            {0x0116, "PropertyTagRowsPerStrip"},
            {0x0153, "PropertyTagSampleFormat"},
            {0x0115, "PropertyTagSamplesPerPixel"},
            {0x0155, "PropertyTagSMaxSampleValue"},
            {0x0154, "PropertyTagSMinSampleValue"},
            {0x0131, "PropertyTagSoftwareUsed"},
            {0x0303, "PropertyTagSRGBRenderingIntent"},
            {0x0117, "PropertyTagStripBytesCount"},
            {0x0111, "PropertyTagStripOffsets"},
            {0x00FF, "PropertyTagSubfileType"},
            {0x0124, "PropertyTagT4Option"},
            {0x0125, "PropertyTagT6Option"},
            {0x0151, "PropertyTagTargetPrinter"},
            {0x0107, "PropertyTagThreshHolding"},
            {0x5034, "PropertyTagThumbnailArtist"},
            {0x5022, "PropertyTagThumbnailBitsPerSample"},
            {0x5015, "PropertyTagThumbnailColorDepth"},
            {0x5019, "PropertyTagThumbnailCompressedSize"},
            {0x5023, "PropertyTagThumbnailCompression"},
            {0x503B, "PropertyTagThumbnailCopyRight"},
            {0x501B, "PropertyTagThumbnailData"},
            {0x5033, "PropertyTagThumbnailDateTime"},
            {0x5026, "PropertyTagThumbnailEquipMake"},
            {0x5027, "PropertyTagThumbnailEquipModel"},
            {0x5012, "PropertyTagThumbnailFormat"},
            {0x5014, "PropertyTagThumbnailHeight"},
            {0x5025, "PropertyTagThumbnailImageDescription"},
            {0x5021, "PropertyTagThumbnailImageHeight"},
            {0x5020, "PropertyTagThumbnailImageWidth"},
            {0x5029, "PropertyTagThumbnailOrientation"},
            {0x5024, "PropertyTagThumbnailPhotometricInterp"},
            {0x502F, "PropertyTagThumbnailPlanarConfig"},
            {0x5016, "PropertyTagThumbnailPlanes"},
            {0x5036, "PropertyTagThumbnailPrimaryChromaticities"},
            {0x5017, "PropertyTagThumbnailRawBytes"},
            {0x503A, "PropertyTagThumbnailRefBlackWhite"},
            {0x5030, "PropertyTagThumbnailResolutionUnit"},
            {0x502D, "PropertyTagThumbnailResolutionX"},
            {0x502E, "PropertyTagThumbnailResolutionY"},
            {0x502B, "PropertyTagThumbnailRowsPerStrip"},
            {0x502A, "PropertyTagThumbnailSamplesPerPixel"},
            {0x5018, "PropertyTagThumbnailSize"},
            {0x5032, "PropertyTagThumbnailSoftwareUsed"},
            {0x502C, "PropertyTagThumbnailStripBytesCount"},
            {0x5028, "PropertyTagThumbnailStripOffsets"},
            {0x5031, "PropertyTagThumbnailTransferFunction"},
            {0x5035, "PropertyTagThumbnailWhitePoint"},
            {0x5013, "PropertyTagThumbnailWidth"},
            {0x5037, "PropertyTagThumbnailYCbCrCoefficients"},
            {0x5039, "PropertyTagThumbnailYCbCrPositioning"},
            {0x5038, "PropertyTagThumbnailYCbCrSubsampling"},
            {0x0145, "PropertyTagTileByteCounts"},
            {0x0143, "PropertyTagTileLength"},
            {0x0144, "PropertyTagTileOffset"},
            {0x0142, "PropertyTagTileWidth"},
            {0x012D, "PropertyTagTransferFunction"},
            {0x0156, "PropertyTagTransferRange"},
            {0x013E, "PropertyTagWhitePoint"},
            {0x011E, "PropertyTagXPosition"},
            {0x011A, "PropertyTagXResolution"},
            {0x0211, "PropertyTagYCbCrCoefficients"},
            {0x0213, "PropertyTagYCbCrPositioning"},
            {0x0212, "PropertyTagYCbCrSubsampling"},
            {0x011F, "PropertyTagYPosition"},
            {0x011B, "PropertyTagYResolution"},
        };

        public static string ReadPropertValueAsString(this PropertyItem propItem)
        {
            switch (propItem.Type)
            {
                case BYTES:
                    {
                        return propItem.Value.ToCommaSeparatedString();
                    }
                case ASCII: 
                    {
                        return System.Text.Encoding.ASCII.GetString(propItem.Value).TrimEnd('\0');
                    }
                case SHORT: 
                    {
                        var value = propItem.Value;
                        var ret = new ushort[propItem.Len / 2];
                        for (int i = 0; i < propItem.Len; i += 2)
                        {
                            ret[i / 2] = (ushort)(value[i + 1] << 8 | value[i]);
                        }
                        return ret.ToCommaSeparatedString();
                    }
                case LONG:
                case RATIONAL:
                    {
                        var value = propItem.Value;
                        var ret = new uint[propItem.Len / 4];
                        for (int i = 0; i < propItem.Len; i += 4)
                        {
                            ret[i / 4] = (uint)(value[i + 3] << 24 | value[i + 2] << 16 | value[i + 1] << 8 | value[i]);
                        }
                        return ret.ToCommaSeparatedString();
                    }
                case SLONG:
                case SRATIONAL:
                    {
                        var value = propItem.Value;
                        var ret = new int[propItem.Len / 4];
                        for (int i = 0; i < propItem.Len; i += 4)
                        {
                            ret[i / 4] = value[i + 3] << 24 | value[i + 2] << 16 | value[i + 1] << 8 | value[i];
                        }
                        return ret.ToCommaSeparatedString();
                    }
                default:
                    return "";
            }
        }

        private static string ToCommaSeparatedString<T>(this ICollection<T> collection)
        {
            return collection != null ? string.Join(",", collection.ToArray()) : null;
        }

        private static string Trim(this string text, int limit, string suffix="...")
        {
            if (text.Length > limit)
            {
                return text.Substring(0, limit) + suffix;
            }
            return text;
        }
    }
}

コメント

このブログの人気の投稿

Eclipseでコードカバレッジのハイライトを削除する方法

Eclipseには便利なコードカバレッジ表示機能が搭載されていますが、コード内に緑、赤、黄の色付けがされて煩く感じるときもあると思います。 1度カバレッジの色付けが出てしまった後に消す方法の紹介です(方法は簡単)。 下記のキャプチャの青いマーカーで示した「Remove All Sessions」のボタンを押せばすべて消えます。

「特定の文字から始まらない文字列」にマッチする正規表現

「特定の文字から始まらない文字列」 にマッチする正規表現の例です。  以下の例では、Aから始まらない文字列にマッチする正規表現を示しています。 ^(?!A).*$ 私も正規表現の組み方で四苦八苦することがあります。以下の書籍は実践的に様々な正規表現のパターンを例示してくれているので、重宝しています。

ダイソーで買った200円のドライバーセットでHDDを分解

HDDの処分 最近は個人情報の問題もあって、HDDを処分する前にちゃんとデータの消去を気にすることも多くなってきました。消去方法としては大きく分けて下記の3つがあります。 データ消去ソフトでフォーマット HDD内部のプラッタを物理破壊 データ消去を行ってくれる専門の業者や家電量販店(Sofmapやビックカメラで実施していると思います。費用発生。)に持ち込み。 データ消去ソフトでのフォーマットは簡単ですが、欠点として「フォーマットに時間がかかる」「セクタ破損などで中途半端に壊れたディスクのフォーマットができない」などがあります。 またHDD内部のプラッタの物理破壊については、HDDを分解するために、通常のプラスやマイナスドライバーではなく、星形ネジに対応したトルクスドライバーが必要とのこともあって、少し面倒です。 筆者は今回、今後もHDDの廃棄をするだろうなあと思い、思い切って自分で分解して廃棄することにチャレンジしてみました。(家電量販店に持って行くよりも安くできないかというどケチ丸出しですw) HDDの星形ネジ こんなやつです。ちなみに写真はSeagateのST2000DL003というHDDで撮影しました。 トルクスドライバー というわけで、分解のために Amazonでトルクスドライバー を探しました。 調べると T8のもだと使えそう とのことで、いろいろと物色。 セットのものとか T8一本で立派なやつとか 色々あったのですが、HDD壊すだけで800円かぁ(←どケチ)、と思って購入を躊躇。 ネット上で調べると100円ショップのダイソーでも、トルクスドライバーを販売しているとの情報をキャッチ!近所のダイソーに行って、探したところ星形のヘッド交換に対応した精密ドライバーセットがありました。 プラスが10種類、マイナスが8種類、六角が6種類、星形が6種類(今回ほしかったもの)のセットで、何とお値段税抜き200円!、税抜き200円!と安かったので、ダメもとで購入しました。 結論から言うと 買って大正解 でした。 ダイソーの精密ドライバーセット こんな商品です! 星形対応のヘッドを装着するとこんな感じ。ドライバーのグリップもゴムで滑らない様になっていて使いやす...

SQLで特定の文字を組み合わせたランダムな文字列を生成

簡易的な方法として「指定した文字列からランダムに1文字選ぶ」を必要な文字の長さ分concat関数でつなげれば実現できます。 1文字ずつ文字を選ぶので、あまり性能もよくない上、セキュリティ的な観点からのランダム性も担保されていないので、あくまで開発中に必要になった時に使う程度が無難だと思います。 下記に英数字大文字小文字を含んだランダムな3文字の文字列を生成するクエリを示します。 # RAND関数で指定した文字列からランダムに1文字選択。 # 下記の例の62の部分はa~z、A~Z、1~9の文字数の合計値を入れた結果 SELECT CONCAT( SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1) ) AS random_string;

PHPの配列(array)のメモリ使用量の考察

はじめに 最近PHP上に大量のデータをメモリ上に展開していたのですが、配列(array)の形式(連想配列 or 単純な配列)や配列の要素のデータ構造(数字、配列、文字列など)で大きくメモリ使用量に差が出てくることに気づき、簡単なプログラムを組んで調べてみました。 あくまで筆者の環境での結果なので、細かい数値は参考程度に見てください。 測定環境と方法 OS: Windows 10 PHP 7.4.5 (php-7.4.5-nts-Win32-vc15-x64) 配列に要素を追加するプログラムを書いて、PHPのmemory_get_usage(true)関数を使って実メモリ使用量を計測しました。 計測結果 No. 方式 1MB当たり作成できる 要素数 プログラム 補足 1 キーも値も整数の配列 (整数IDを想定) 28571 // 2,000,000 / 70MB $row = []; for($i = 0; $i < 2000000; $i++) { $row[] = $i; } No.2~6でテストしたプログラム中の要素数は200,000。これだけ一桁多い! 2 キーが文字列、値が整数の連想配列 8333 // 200,000 / 24MB $row = []; for($i = 0; $i < 200000; $i++) { $row[$i.'_key_string'] = $i; } キーの文字列が長い方がメモリ使用量多くなる。 3 キーが整数、値が連想配列の配列 DBから取得してきたデータを想定 2325 // 200,000 / 86MB $row = []; for($i = 0; $i < 200000; $i++) { row[] = ['id' => $i]; } 4 キーが整数、値が連想配列の配列(配列に複数の値を保持) DBから取得してきたデータを想定 2127 // 200,000 /...

ADODB.streamオブジェクトを使って文字列とByte配列を相互変換(Excel VBA)

ADODB.streamオブジェクトを使って文字列をByte配列に変換するコードのサンプルです。 ExcelVBAでADODB.streamを使う際には、 1. ExcelのMicrosoft Visual Basic エディタのメニューバーから「ツール->参照設定」とたどる。 2. 表示されたダイアログからMicrosoft ActiveX Data Objectsにチェックを入れる。 という手順が必要です。 文字列からByte配列へ Private Function ADOS_EncodeStringToByte(ByVal cset As String, ByRef strUni As String) As Byte() On Error GoTo e Dim objStm As ADODB.stream: Set objStm = New ADODB.stream objStm.Mode = adModeReadWrite objStm.Open objStm.Type = adTypeText objStm.Charset = cset objStm.WriteText strUni objStm.Position = 0 objStm.Type = adTypeBinary Select Case UCase(cset) Case "UNICODE", "UTF-16" objStm.Position = 2 Case "UTF-8" objStm.Position = 3 End Select ADOS_EncodeStringToByte = objStm.Read() objStm.Close Set objStm = Nothing Exit Function e: Debug.Print "Error occurred while encoding characters" & Err.Description If objStm Is No...

Visual Studio 2010 SP1のアンインストール

Visual Studio 2013に乗り換えるためにVisual Studio 2010をアンインストールしようとしたところで問題発生。。。 先にVisual Studio 2010本体をアンインストールした後、Visual Studio 2010 SP1をアンインストールできなくて困っていました。 Google先生で調べたところ、以下の情報が見つかり、書かれていた通り実施したところ無事Visual Studio 2010 SP1のアンインストールに成功しました。 How to uninstall/remove Visual Studio SP1 アンインストール手順は以下の通りです。 http://www.microsoft.com/en-gb/download/details.aspx?id=23691 からMicrosoft Visual Studio 2010 Service Pack 1 (Installer)をダウンロード VS10sp1-KB983509.exeというファイル名でダウンロードされる(はず)。 コマンドプロンプトから以下のコマンドを実行 (以下の例は、c:\tempにVS10sp1-KB983509.exeがある場合) c:\temp\VS10sp1-KB983509.exe /uninstall /force ダイアログが立ち上がるので、アンインストールを選択して次へ進めばOK!

MySQL: SELECTの結果をUNIONして ORDER BYする際の最適化方法

SELECTの結果をUNIONして ORDER BY する際には下記の点に注意する必要があります。 無駄なメモリ消費 ソートにINDEXが利かない (≒CPU負荷増大) 対応策 可能であればPush-down Condition (各サブクエリ内でORDER BY, LIMIT, OFFSETを適用してからUNION, ORDER BYを実行する)を利用することで、 パフォーマンスを改善できる場合があります。 下記に例を示します。 もともとのクエリ SELECT tmp.* FROM ( SELECT tableA.column1, tableA.column2 FROM tableA WHERE (条件) UNION ALL SELECT tableB.column1, tableB.column2 FROM tableB WHERE (条件) ) AS tmp ORDER BY tmp.column1, tmp.column2 LIMIT 100, 20 Push-down Conditionを用いて書き直したクエリ SELECT tmp.* FROM ( SELECT tableA.column1, tableA.column2 FROM tableA WHERE (条件) ORDER BY tableA.column1, tableA.column2 LIMIT 30 # ただしこのPush-down Conditionの手法も下記の場合は、効果が半減しますので注意が必要です。 OFFSETの値が大きい場合は、結局全結果セットUNIONと変わらない サブクエリ内のソートで、INDEXが効かない場合

PHPでファイルを指定した行数ごとに分割

ファイルを指定した行数ごとに分割するためには、Linuxのsplitコマンドを使えば簡単に実現できます。 PHPではexec関数にsplitコマンドを渡して実行すればよいですが、下記の弱点があります。 Linuxのコマンドに依存 (PHPの場合はほとんどLinux環境で動作させることが普通なのでそこまで問題にならないかも知れません)。 exec関数は慎重に引数を渡さないと、OSコマンドインジェクション脆弱性を引き起こす可能性がある。 そこで、今回はPHPでファイルを指定した行数ごとに分割するプログラムを書いてみました。 <?php class FileSplitter { private $lines; private $fileCount; public function split($filePath, $linesPerFile, $outputDir) { $this->fileCount = 0; $this->lines = null; $file = new \SplFileObject($filePath); $lineCount = 0; try{ while (!$file->eof()) { if($lineCount % $linesPerFile === 0) { $this->writeToFile($this->generateOutputFilePath($outputDir, $file)); } $this->lines[] = $file->fgets(); $lineCount++; } $this->writeToFile($this->generateOutpu...

MySQLでGROUP_CONCATしたフィールドに対して疑似的にLIMITを実現する方法

MySQLでGROUP_CONCATしたフィールドに対して疑似的にLIMITを実現するには、GROUP_CONCATで生成された文字列に対して、SUBSTRING_INDEXを使って文字列を切り出す方法が簡単です。 # 下記はid, codeをカラムに持つテーブルで、codeカラムでGROUP BYして、codeごとにidをlimitで取得する例です。 SELECT code ,SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY id DESC), ',', :limit) # :limitの部分に取得したい件数を指定。 FROM table GROUP BY code 長所は、下記のように条件を指定して、LIMIT句で取得件数を指定したクエリを何度も発行する必要がないところです。 特に、一回あたりクエリの発行コストが高い場合は、GROUP_CONCATを使って一度に取得したほうが最終的な実行時間をかなり節約することができます。 SELECT id FROM table WHERE code = 'A' ORDER BY id DESC LIMIT :limit; ただし、短所も多いので、使用する際は、これらの短所について十分に考慮したうえで使ってください。 GROUP_CONCATで生成された文字列に対して、SUBSTRING_INDEXを使って文字列を切り出すという文字列処理なので、無駄が多い。 特にGROUP_CONCATで生成された元の文字列が長い場合。 GROUP_CONCATの区切り文字が、GROUP_CONCATされる元の文字列に含まれていると正しくLIMITされない。 例:GROUP_CONCATされる元の文字列にカンマが含まれているのに、カンマを区切り文字で指定している場合。 GROUP_CONCATの最大文字数制限を超えた場合は、機能しない。 MySQLのGROUP_CONCATの最大文字数制限は、「SHOW VARIABLES LIKE '%group_concat%';」で調べられます。デフォルト値は1024のようです。 ...