YYKit 源码探究 NSString+YYAdd(一)

2023-04-02  本文已影响0人  一个小白iOS

前言

YYKit是iOS组件的集合,这个框架的代码量很大,这里就分出几个独立的部分。

安装

CocoaPods

基本框架

下面我们就看一下YYKit的基本框架。


WeChat49c9ea940bac96a3e0f1e82e270c3a99.png image.png
image.png
image.png
image.png

NSString+YYAdd 框架

基本结构

下面我们来看下NSString分类 NSString+YYAdd 的架构,如下图所示


image.png

其实这里面包含了六个部分:

接下来,我们就将一部分一部分的进行分析其接口API

一、Hash

下面我们来看看Hash这部分的接口

#pragma mark - Hash
///=============================================================================
/// @name Hash
///=============================================================================

/**
 Returns a lowercase NSString for md2 hash.
 */
- (nullable NSString *)md2String;

/**
 Returns a lowercase NSString for md4 hash.
 */
- (nullable NSString *)md4String;

/**
 Returns a lowercase NSString for md5 hash.
 */
- (nullable NSString *)md5String;

/**
 Returns a lowercase NSString for sha1 hash.
 */
- (nullable NSString *)sha1String;

/**
 Returns a lowercase NSString for sha224 hash.
 */
- (nullable NSString *)sha224String;

/**
 Returns a lowercase NSString for sha256 hash.
 */
- (nullable NSString *)sha256String;

/**
 Returns a lowercase NSString for sha384 hash.
 */
- (nullable NSString *)sha384String;

/**
 Returns a lowercase NSString for sha512 hash.
 */
- (nullable NSString *)sha512String;

/**
 Returns a lowercase NSString for hmac using algorithm md5 with key.
 @param key The hmac key.
 */
- (nullable NSString *)hmacMD5StringWithKey:(NSString *)key;

/**
 Returns a lowercase NSString for hmac using algorithm sha1 with key.
 @param key The hmac key.
 */
- (nullable NSString *)hmacSHA1StringWithKey:(NSString *)key;

/**
 Returns a lowercase NSString for hmac using algorithm sha224 with key.
 @param key The hmac key.
 */
- (nullable NSString *)hmacSHA224StringWithKey:(NSString *)key;

/**
 Returns a lowercase NSString for hmac using algorithm sha256 with key.
 @param key The hmac key.
 */
- (nullable NSString *)hmacSHA256StringWithKey:(NSString *)key;

/**
 Returns a lowercase NSString for hmac using algorithm sha384 with key.
 @param key The hmac key.
 */
- (nullable NSString *)hmacSHA384StringWithKey:(NSString *)key;

/**
 Returns a lowercase NSString for hmac using algorithm sha512 with key.
 @param key The hmac key.
 */
- (nullable NSString *)hmacSHA512StringWithKey:(NSString *)key;

/**
 Returns a lowercase NSString for crc32 hash.
 */
- (nullable NSString *)crc32String;

其实这部分接口做的是两部分的功能:

下面我们就对指定的两个具有代表性的方法实现进行说明和解析。

sha512

首先我们看一下这个方法的接口调用示例和实现。

1. 接口调用示例
/**
 Returns a lowercase NSString for sha512 hash.
 */
- (nullable NSString *)sha512String;

下面我们就调用一下

    NSString *str = @"abcdefgh";
    NSString *sha512Str = [str sha512String];
    NSLog(@"sha512Str = %@",sha512Str);
    NSLog(@"sha512Str length = %ld",sha512Str.length);

接着我们看一下输出结果:

2023-04-03 14:02:42.331463+0800 YYKitDemo[866:3899739] sha512Str = a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce
2023-04-03 14:02:42.331545+0800 YYKitDemo[866:3899739] sha512Str length = 128

可以看见,加密后数据为128位十六进制数,换算成二进制数就是512位

2.接口实现

下面我们就看一下接口的实现

- (NSString *)sha512String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] sha512String];
}

这里首先调用的就是系统的 NSString 接口 dataUseingEncoding: 方法,将NSString转换为NSData对象,- (nullable NSData *)dataUsingEncoding:(NSStringEncoding)encoding 。

下面这里就是调用 NSData+YYAdd分类里面的方法sha512String,将NSData对象进行加密后转化为NSString对象

- (NSString *)sha512String {
    unsigned char result[CC_SHA512_DIGEST_LENGTH];
    CC_SHA512(self.bytes, (CC_LONG)self.length, result);
    NSMutableString *hash = [NSMutableString
                             stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++) {
        [hash appendFormat:@"%02x", result[i]];
    }
    return hash;
}

上面就是简单的实现,其他sha224等的实现都是类似的。

带key的sha512

首先我们看一下这个方法的接口调用示例和实现

1.示例
    NSString *str = @"abcdefgh";
    NSString *sha512Str = [str hmacSHA512StringWithKey:@"zzz"];
    NSLog(@"sha512Str = %@",sha512Str);
    NSLog(@"sha512Str length = %ld",sha512Str.length);
2023-04-03 14:10:49.802227+0800 YYKitDemo[1155:3910766] sha512Str = e64db1c1b01c362931b283d28cfbf6baafd807c10cf07328cda9b37fb73b4571a76beb15d7dc6d16888d593a233974679af8a49e0543edbfeab8790eb86bb5c9
2023-04-03 14:10:49.802351+0800 YYKitDemo[1155:3910766] sha512Str length = 128
接口实现
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
    return [[self dataUsingEncoding:NSUTF8StringEncoding]
            hmacSHA512StringWithKey:key];
}

下面就是NSData的分类里面了

- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
    return [self hmacStringUsingAlg:kCCHmacAlgSHA512 withKey:key];
}
- (NSString *)hmacStringUsingAlg:(CCHmacAlgorithm)alg withKey:(NSString *)key {
    size_t size;
    switch (alg) {
        case kCCHmacAlgMD5: size = CC_MD5_DIGEST_LENGTH; break;
        case kCCHmacAlgSHA1: size = CC_SHA1_DIGEST_LENGTH; break;
        case kCCHmacAlgSHA224: size = CC_SHA224_DIGEST_LENGTH; break;
        case kCCHmacAlgSHA256: size = CC_SHA256_DIGEST_LENGTH; break;
        case kCCHmacAlgSHA384: size = CC_SHA384_DIGEST_LENGTH; break;
        case kCCHmacAlgSHA512: size = CC_SHA512_DIGEST_LENGTH; break;
        default: return nil;
    }
    unsigned char result[size];
    const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
    CCHmac(alg, cKey, strlen(cKey), self.bytes, self.length, result);
    NSMutableString *hash = [NSMutableString stringWithCapacity:size * 2];
    for (int i = 0; i < size; i++) {
        [hash appendFormat:@"%02x", result[i]];
    }
    return hash;
}

这个也很好理解,和上面不带key的方法实现相比,不同的是这里用的是系统方法 CCHmac。

二、Encode and decode

主要是包括:base64编码和解码、URL的UTF-8编码以及常见的HTML转义实体。原理同上

HTML转义实体: 例如 a > b 转义后 a<b

三、Drawing

- (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode

这个方法的作用就是返回给定的字符串边界的宽度和高度。这里size参数的意思是字符串的最大可接受大小。此值用于计算行会发生断裂和换行的位置

示例
    NSString *str1 = @"说法发链接嘎嘎我给我阿萨法久啊射流风机萨芬较大生发剂噶防静电撒发发设计费萨法大丰收地方大";
    CGSize stringSize = [str1 sizeForFont:[UIFont systemFontOfSize:16.0] size:CGSizeMake(200, 500) mode:NSLineBreakByCharWrapping];
    NSLog(@"字符串的大小为 = %@",NSStringFromCGSize(stringSize));

输出结果

2023-04-03 14:28:20.489941+0800 YYKitDemo[1548:3929096] 字符串的大小为 = {195.84, 76.375}
方法的实现
image.png

这里其实还是利用NSString的原生方法

boundingRectWithSize: options: attributes: context:

其他方法同理

例如:

- (CGFloat)widthForFont:(UIFont *)font;
image.png

此处传入的size为最大值

传入的换行模式为:NSLineBreakByWordWrapping

四、Regular Expression

我们来详细的看一下这个接口 API

- (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options;

该方法的作用是根据固定的匹配的表达式,判断给定的字符串和调用者是否匹配

示例
    NSString *str2 = @"A";
    BOOL isMatch = [str2 matchesRegex:@"B" options:NSRegularExpressionCaseInsensitive];
    NSLog(@"是否匹配 = %d",isMatch);

打印结果:

2023-04-03 14:38:28.890424+0800 YYKitDemo[1794:3941628] 是否匹配 = 0

示例二:

    NSString *str3 = @"A";
    BOOL isMatch1 = [str3 matchesRegex:@"a" options:NSRegularExpressionCaseInsensitive];
    NSLog(@"是否匹配 = %d",isMatch1);

打印结果:

2023-04-03 14:39:28.956567+0800 YYKitDemo[1829:3943455] 是否匹配 = 1

上面这个例子 NSRegularExpressionCaseInsensitive 也就是不区分大小写的比较。

方法的实现
- (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options {
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:NULL];
    if (!pattern) return NO;
    return ([pattern numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)] > 0);
}

方法中有一个枚举值,就是 NSRegularExpressionOptions 下面我们就看一下这个枚举值。

typedef NS_OPTIONS(NSUInteger, NSRegularExpressionOptions) {
   NSRegularExpressionCaseInsensitive             = 1 << 0,     /* Match letters in the pattern independent of case. */
   NSRegularExpressionAllowCommentsAndWhitespace  = 1 << 1,     /* Ignore whitespace and #-prefixed comments in the pattern. */
   NSRegularExpressionIgnoreMetacharacters        = 1 << 2,     /* Treat the entire pattern as a literal string. */
   NSRegularExpressionDotMatchesLineSeparators    = 1 << 3,     /* Allow . to match any character, including line separators. */
   NSRegularExpressionAnchorsMatchLines           = 1 << 4,     /* Allow ^ and $ to match the start and end of lines. */
   NSRegularExpressionUseUnixLineSeparators       = 1 << 5,     /* Treat only \n as a line separator (otherwise, all standard line separators are used). */
   NSRegularExpressionUseUnicodeWordBoundaries    = 1 << 6      /* Use Unicode TR#29 to specify word boundaries (otherwise, traditional regular expression word boundaries are used). */
};

对应的值表示的意义:

   NSRegularExpressionCaseInsensitive              = 1 << 0,   // 不区分大小写的
   NSRegularExpressionAllowCommentsAndWhitespace   = 1 << 1,   // 忽略空格和
   NSRegularExpressionIgnoreMetacharacters     = 1 << 2,   // 整体化
   NSRegularExpressionDotMatchesLineSeparators     = 1 << 3, // 匹配任何字符,包括行分隔符
   NSRegularExpressionAnchorsMatchLines        = 1 << 4, // 允许^和$在匹配的开始和结束行
   NSRegularExpressionUseUnixLineSeparators    = 1 << 5, // (查找范围为整个的话无效)
   NSRegularExpressionUseUnicodeWordBoundaries     = 1 << 6 // (查找范围为整个的话无效)

五、NSNumber Compatible

示例
    NSString *str4 = @"1234577045";
    long value = [str4 longValue];
    NSLog(@"值为 = %ld",value);
实现
- (NSNumber *)numberValue {
    return [NSNumber numberWithString:self];
}

最后就是进入NSNumber的分类进行了处理

+ (NSNumber *)numberWithString:(NSString *)string {
    NSString *str = [[string stringByTrim] lowercaseString];
    if (!str || !str.length) {
        return nil;
    }
    
    static NSDictionary *dic;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dic = @{@"true" :   @(YES),
                @"yes" :    @(YES),
                @"false" :  @(NO),
                @"no" :     @(NO),
                @"nil" :    [NSNull null],
                @"null" :   [NSNull null],
                @"<null>" : [NSNull null]};
    });
    id num = dic[str];
    if (num) {
        if (num == [NSNull null]) return nil;
        return num;
    }
    
    // hex number
    int sign = 0;
    if ([str hasPrefix:@"0x"]) sign = 1;
    else if ([str hasPrefix:@"-0x"]) sign = -1;
    if (sign != 0) {
        NSScanner *scan = [NSScanner scannerWithString:str];
        unsigned num = -1;
        BOOL suc = [scan scanHexInt:&num];
        if (suc)
            return [NSNumber numberWithLong:((long)num * sign)];
        else
            return nil;
    }
    // normal number
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
    return [formatter numberFromString:string];
}

六、Utilities

下面我们看一下API接口。

#pragma mark - Utilities
///=============================================================================
/// @name Utilities
///=============================================================================

/**
 Returns a new UUID NSString
 e.g. "D1178E50-2A4D-4F1F-9BD3-F6AAB00E06B1"
 */
+ (NSString *)stringWithUUID;

/**
 Returns a string containing the characters in a given UTF32Char.
 
 @param char32 A UTF-32 character.
 @return A new string, or nil if the character is invalid.
 */
+ (nullable NSString *)stringWithUTF32Char:(UTF32Char)char32;

/**
 Returns a string containing the characters in a given UTF32Char array.
 
 @param char32 An array of UTF-32 character.
 @param length The character count in array.
 @return A new string, or nil if an error occurs.
 */
+ (nullable NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length;

/**
 Enumerates the unicode characters (UTF-32) in the specified range of the string.
 
 @param range The range within the string to enumerate substrings.
 @param block The block executed for the enumeration. The block takes four arguments:
    char32: The unicode character.
    range: The range in receiver. If the range.length is 1, the character is in BMP;
        otherwise (range.length is 2) the character is in none-BMP Plane and stored
        by a surrogate pair in the receiver.
    stop: A reference to a Boolean value that the block can use to stop the enumeration 
        by setting *stop = YES; it should not touch *stop otherwise.
 */
- (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block;

/**
 Trim blank characters (space and newline) in head and tail.
 @return the trimmed string.
 */
- (NSString *)stringByTrim;

/**
 Add scale modifier to the file name (without path extension),
 From @"name" to @"name@2x".
 
 e.g.
 <table>
 <tr><th>Before     </th><th>After(scale:2)</th></tr>
 <tr><td>"icon"     </td><td>"icon@2x"     </td></tr>
 <tr><td>"icon "    </td><td>"icon @2x"    </td></tr>
 <tr><td>"icon.top" </td><td>"icon.top@2x" </td></tr>
 <tr><td>"/p/name"  </td><td>"/p/name@2x"  </td></tr>
 <tr><td>"/path/"   </td><td>"/path/"      </td></tr>
 </table>
 
 @param scale Resource scale.
 @return String by add scale modifier, or just return if it's not end with file name.
 */
- (NSString *)stringByAppendingNameScale:(CGFloat)scale;

/**
 Add scale modifier to the file path (with path extension),
 From @"name.png" to @"name@2x.png".
 
 e.g.
 <table>
 <tr><th>Before     </th><th>After(scale:2)</th></tr>
 <tr><td>"icon.png" </td><td>"icon@2x.png" </td></tr>
 <tr><td>"icon..png"</td><td>"icon.@2x.png"</td></tr>
 <tr><td>"icon"     </td><td>"icon@2x"     </td></tr>
 <tr><td>"icon "    </td><td>"icon @2x"    </td></tr>
 <tr><td>"icon."    </td><td>"icon.@2x"    </td></tr>
 <tr><td>"/p/name"  </td><td>"/p/name@2x"  </td></tr>
 <tr><td>"/path/"   </td><td>"/path/"      </td></tr>
 </table>
 
 @param scale Resource scale.
 @return String by add scale modifier, or just return if it's not end with file name.
 */
- (NSString *)stringByAppendingPathScale:(CGFloat)scale;

/**
 Return the path scale.
 
 e.g.
 <table>
 <tr><th>Path            </th><th>Scale </th></tr>
 <tr><td>"icon.png"      </td><td>1     </td></tr>
 <tr><td>"icon@2x.png"   </td><td>2     </td></tr>
 <tr><td>"icon@2.5x.png" </td><td>2.5   </td></tr>
 <tr><td>"icon@2x"       </td><td>1     </td></tr>
 <tr><td>"icon@2x..png"  </td><td>1     </td></tr>
 <tr><td>"icon@2x.png/"  </td><td>1     </td></tr>
 </table>
 */
- (CGFloat)pathScale;

/**
 nil, @"", @"  ", @"\n" will Returns NO; otherwise Returns YES.
 */
- (BOOL)isNotBlank;

/**
 Returns YES if the target string is contained within the receiver.
 @param string A string to test the the receiver.
 
 @discussion Apple has implemented this method in iOS8.
 */
- (BOOL)containsString:(NSString *)string;

/**
 Returns YES if the target CharacterSet is contained within the receiver.
 @param set  A character set to test the the receiver.
 */
- (BOOL)containsCharacterSet:(NSCharacterSet *)set;

/**
 Try to parse this string and returns an `NSNumber`.
 @return Returns an `NSNumber` if parse succeed, or nil if an error occurs.
 */
- (nullable NSNumber *)numberValue;

/**
 Returns an NSData using UTF-8 encoding.
 */
- (nullable NSData *)dataValue;

/**
 Returns NSMakeRange(0, self.length).
 */
- (NSRange)rangeOfAll;

/**
 Returns an NSDictionary/NSArray which is decoded from receiver.
 Returns nil if an error occurs.
 
 e.g. NSString: @"{"name":"a","count":2}"  => NSDictionary: @[@"name":@"a",@"count":@2]
 */
- (nullable id)jsonValueDecoded;

/**
 Create a string from the file in main bundle (similar to [UIImage imageNamed:]).
 
 @param name The file name (in main bundle).
 
 @return A new string create from the file in UTF-8 character encoding.
 */
+ (nullable NSString *)stringNamed:(NSString *)name;

1. + (NSString *)stringWithUUID;

该方法返回的是UUID字符串。

示例调用
    NSString *resultStr = [NSString stringWithUUID];
    NSLog(@"UUID为 = %@", resultStr);
输出结果
2023-04-03 14:56:14.138679+0800 YYKitDemo[2210:3962979] UUID为 = F2F21473-6B4A-4C0C-9574-7DB7DFE3E272
方法实现
+ (NSString *)stringWithUUID {
    CFUUIDRef uuid = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, uuid);
    CFRelease(uuid);
    return (__bridge_transfer NSString *)string;
}

2. + (nullable NSString *)stringWithUTF32Char:(UTF32Char)char32;

该方法的作用就是将给定的UTF32Char类型的字符转化为一个NSString类型的字符串,如果这个字符是无效的,那么转化的字符串为nil。

示例调用
    UTF32Char number = 97;
    NSString *resultStr1 = [NSString stringWithUTF32Char:number];
    NSLog(@"resultStr = %@", resultStr1);

输出结果:

2023-04-03 14:58:03.797956+0800 YYKitDemo[2268:3966023] resultStr = a
方法实现
+ (NSString *)stringWithUTF32Char:(UTF32Char)char32 {
    char32 = NSSwapHostIntToLittle(char32);
    return [[NSString alloc] initWithBytes:&char32 length:4 encoding:NSUTF32LittleEndianStringEncoding];
}

上面方法的实现中调用的两个方法均为系统内部的方法。

3. + (nullable NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length;

该方法的作用就是根据给定的 UTF-32字符组和长度,返回一个字符串。

示例调用
    UTF32Char test = 98;
    NSString *resultStr2 = [NSString stringWithUTF32Chars:&test length:1];
    NSLog(@"resultStr = %@", resultStr2);
打印结果
2023-04-03 15:02:26.808306+0800 YYKitDemo[2425:3973674] resultStr = b
方法实现
+ (NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length {
    return [[NSString alloc] initWithBytes:(const void *)char32
                                    length:length * 4
                                  encoding:NSUTF32LittleEndianStringEncoding];
}

4. - (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block;

枚举字符串指定范围内的Unicode字符(UTF-32),这里需要说明下几个参数:

示例调用
    NSString *str5 = @"abdsdfda";
    [str5 enumerateUTF32CharInRange:NSMakeRange(0, 3) usingBlock:^(UTF32Char char32, NSRange range, BOOL * _Nonnull stop) {
        NSLog(@"字符是 %d",char32);
    }];

打印结果

2023-04-03 15:10:40.178462+0800 YYKitDemo[2638:3983694] 字符是 97
2023-04-03 15:10:40.178535+0800 YYKitDemo[2638:3983694] 字符是 98
2023-04-03 15:10:40.178617+0800 YYKitDemo[2638:3983694] 字符是 100

下面看一下该方法的实现

- (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block {
    NSString *str = self;
    if (range.location != 0 || range.length != self.length) {
        str = [self substringWithRange:range];
    }
    NSUInteger len = [str lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
    UTF32Char *char32 = (UTF32Char *)[str cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
    if (len == 0 || char32 == NULL) return;
    
    NSUInteger location = 0;
    BOOL stop = NO;
    NSRange subRange;
    UTF32Char oneChar;
    
    for (NSUInteger i = 0; i < len; i++) {
        oneChar = char32[i];
        subRange = NSMakeRange(location, oneChar > 0xFFFF ? 2 : 1);
        block(oneChar, subRange, &stop);
        if (stop) return;
        location += subRange.length;
    }
}

5. - (NSString *)stringByTrim;

该方法的作用就是修剪头部和尾部的空白字符(空格和换行符)。

6. - (NSString *)stringByAppendingNameScale:(CGFloat)scale;

其实,就是实现类似@"name" 到 @"name@2x"这样的功能。

7. - (NSString *)stringByAppendingPathScale:(CGFloat)scale;

其实就是实现从@"name.png" 到 @"name@2x.png"这样的类似转化。

8. - (CGFloat)pathScale;

9. - (BOOL)isNotBlank;

该方法的作用就是用来判断是否是空白。nil, @"", @" ", @"\n"会返回NO,其他返回YES。

10. - (BOOL)containsString:(NSString *)string;

这个方法很好理解,就是判断一个字符串是否包含另外一个字符串。

11. - (BOOL)containsCharacterSet:(NSCharacterSet *)set;

这个方法的作用就是字符串是否包含某个字符。

12. - (nullable NSNumber *)numberValue;

这个方法就是将字符串转化为NSNumber数据类型,如果不能转换,就返回nil。

13. - (nullable NSData *)dataValue;

这个方法就是将字符串转化为NSData数据类型,使用的是UTF - 8编码。

14. - (NSRange)rangeOfAll;

这个方法就是将返回字符串的range - NSMakeRange(0, self.length)。

15. - (nullable id)jsonValueDecoded;

该方法的作用就是将指定的Json字符串转化为字典或者数组。

16. + (nullable NSString *)stringNamed:(NSString *)name;

该方法的作用就是从main bundle文件中创建字符串,类似于[UIImage imageNamed:]。返回值为文件中UTF - 8编码的字符串。找不到则返回null

上一篇下一篇

猜你喜欢

热点阅读