使用方法比较多,这里列举两种:

第一种:

  1. // 1. 使用AFHTTPSessionManager的接口
  2. AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
  3.  
  4. [manager POST:@"http://123.123.123.1" parameters:@{@"aaa":@""} constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
  5. // 在这个block中设置需要上传的文件
  6. NSString *path = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"jpg"];
  7. // 将本地图片数据拼接到formData中 指定name
  8. // [formData appendPartWithFileURL:[NSURL fileURLWithPath:path] name:@"image" error:nil];
  9.  
  10. // // 或者使用这个接口拼接 指定name和filename
  11. NSData *picdata =[NSData dataWithContentsOfFile:path];
  12. [formData appendPartWithFileData:picdata name:@"image" fileName:@"image.jpg" mimeType:@"image/jpeg"];
  13.  
  14. } progress:^(NSProgress * _Nonnull uploadProgress) {
  15. NSLog(@"progress --- %@",uploadProgress.localizedDescription);
  16. } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
  17. NSLog(@"responseObject-------%@", responseObject);
  18. dispatch_async(dispatch_get_main_queue(), ^{
  19. self.tvres.text = [NSString stringWithFormat:@"响应结果:%@",responseObject];
  20. });
  21. } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
  22. NSLog(@"Error-------%@", error);
  23. }];

第二种:

  1. AFURLSessionManager *sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
  2. // request
  3. NSURL *url = [NSURL URLWithString:@"http://114.215.186.169:9002/api/demo/test/file"];
  4. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  5. [request setHTTPMethod:@"POST"];
  6. // bodydata
  7. //(2)请求头
  8. //上传任务,必须要添加的字段
  9. // 分隔符
  10. //multipart/form-data是必须的,是指提交的表单中有附件
  11. /*
  12. Multipart协议是基于post方法的组合实现,和post协议的主要区别在于请求头和请求体的不同
  13. multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type,且其值也必须规定为multipart/form-data,同时还需要规定一个内容分割符用于分割请求体中的多个post的内容,如文件内容和文本内容自然需要分割开来,不然接收方就无法正常解析和还原这个文件了
  14. multipart/form-data的请求体也是一个字符串,不过和post的请求体不同的是它的构造方式,post是简单的name=value值连接,而multipart/form-data则是添加了分隔符等内容的构造体
  15.  
  16. */
  17. NSString *boundary = @"---------------------------7db15a14291cce";
  18. NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; charset=utf-8;boundary=%@",boundary];
  19. // 设置Content-Type
  20. [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
  21.  
  22. //(3)请求体
  23. NSMutableString *startStr = [NSMutableString string];
  24. // 拼接头部格式
  25. [startStr appendFormat:@"--%@\r\n",boundary];
  26. [startStr appendFormat:@"Content-disposition: form-data; name=\"image\"; filename=\"image.jpg\""];
  27. [startStr appendFormat:@"\r\n"];
  28. [startStr appendFormat:@"Content-Type: application/octet-stream"];
  29. [startStr appendFormat:@"\r\n\r\n"];
  30.  
  31. NSMutableData *bodyData = [NSMutableData data];
  32. NSData *startData = [startStr dataUsingEncoding:NSUTF8StringEncoding];
  33. [bodyData appendData:startData];
  34.  
  35. // 拼接上传文件数据
  36. NSString *path = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"jpg"];
  37. NSData *picdata =[NSData dataWithContentsOfFile:path];
  38. [bodyData appendData:picdata];
  39.  
  40. // 拼接结尾格式
  41. NSString *endStr = [NSString stringWithFormat:@"\r\n--%@--\r\n",boundary];
  42. NSData *endData = [endStr dataUsingEncoding:NSUTF8StringEncoding];
  43. [bodyData appendData:endData];
  44.  
  45. NSURLSessionUploadTask *uploadtask = [sessionManager uploadTaskWithRequest:request fromData:bodyData progress:^(NSProgress * _Nonnull uploadProgress) {
  46. NSLog(@"progress --- %@",uploadProgress.localizedDescription);
  47. } completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
  48.  
  49. NSLog(@"completion --- error:%@",error);
  50. }];
  51. [uploadtask resume];

第二种是靠自己拼凑http header 和 body用于发送给服务端,下面主要分析第一种方法源码的实现。

1 首先进入Post源码

  1. - (NSURLSessionDataTask *)POST:(NSString *)URLString
  2. parameters:(id)parameters
  3. constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
  4. progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
  5. success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
  6. failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
  7. {
  8.  
  9. NSError *serializationError = nil;
  10. //最复杂的在这块
  11. NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
  12. if (serializationError) {
  13. if (failure) {
  14. dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
  15. failure(nil, serializationError);
  16. });
  17. }
  18.  
  19. return nil;
  20. }
  21. __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
  22. if (error) {
  23. if (failure) {
  24. failure(task, error);
  25. }
  26. } else {
  27. if (success) {
  28. success(task, responseObject);
  29. }
  30. }
  31. }];
  32.  
  33. [task resume];
  34.  
  35. return task;
  36. }

首先是创建需要的NSURLRequest,然后新建task,返回task,这里重点说一下标红的地方,NSURLRequest如何组成。

multipartFormRequestWithMethod。

  1. - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
  2. URLString:(NSString *)URLString
  3. parameters:(NSDictionary *)parameters
  4. constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
  5. error:(NSError *__autoreleasing *)error
  6. {
  7. NSParameterAssert(method);
  8. NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]);
  9.  
  10. //调用普通get/post 请求 方法
  11. //这个方法作用:通过 HTTPRequestHeaders 字典设置头部字段,parameters为空,没有处理参数
  12.  
  13. NSMutableURLRequest *mutableRequest = [self requestWithMethod:method URLString:URLString parameters:nil error:error];
  14.  
  15. //初始化AFStreamingMultipartFormData 构建bodyStream
  16. __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:mutableRequest stringEncoding:NSUTF8StringEncoding];
  17.  
  18. if (parameters) {
  19. // 构建一个AFQueryStringPair,其中field为"Filename",value为"文件名"
  20. for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
  21. NSData *data = nil;
  22. if ([pair.value isKindOfClass:[NSData class]]) {
  23. data = pair.value;
  24. } else if ([pair.value isEqual:[NSNull null]]) {
  25. data = [NSData data];
  26. } else {
  27. // 根据对应value的类型,构建出一个NSData变量 把string类型转换为NSData类型数据
  28. data = [[pair.value description] dataUsingEncoding:self.stringEncoding];
  29. }
  30.  
  31. if (data) {
  32. //根据data和name构建Request 消息体的一部分比如 aaa=111
  33. [formData appendPartWithFormData:data name:[pair.field description]];
  34. }
  35. }
  36. }
  37.  
  38. if (block) {
    //从block中添加数据,比如我们可以自己往里添加需要的键值对或者图片资源等
  39. block(formData);
  40. }
  41. //设置一下MultipartRequest的bodyStream或者其特有的content-type
  42. return [formData requestByFinalizingMultipartFormData];
  43. }

进入 requestByFinalizingMultipartFormData 方法

  1. //****************************拼装最终的消息体*******************************/
  2. - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
  3. if ([self.bodyStream isEmpty]) {
  4. return self.request;
  5. }
  6.  
  7. // Reset the initial and final boundaries to ensure correct Content-Length
  8. [self.bodyStream setInitialAndFinalBoundaries];
  9. //把bodyStream交给request处理,request 会调用
  10. /*
  11. [fileStream read:readBuffer maxLength:maxLength];
  12.  
  13. */
  14. //然后我们重写read:,把数据存到eadBuffer
  15. [self.request setHTTPBodyStream:self.bodyStream];
  16. //重新修改Content-Type,表示body中有附件
  17. [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"];
  18. //豹文的长度,多少个字节
  19. [self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"];
  20.  
  21. return self.request;
  22. }

在这个方法里设置requst的输入流,最终是通过从这个流中读取数据配凑的消息体,当然这是request里面封装的,我们看不错,但是可以才猜出来,之后做分析

然后就是重新设置Content-Type,Content-Length.

下面分析下bodyStream:

bodyStream 类对象为 AFMultipartBodyStream,这个类又继承自 NSInputStream,也就是说我们的bodyStream就是一个NSInputStream,里面拥有NSInputStream的功能,我们可以通过重写某些方法,实现我们自己读取数据流的逻辑。

AFStreamingMultipartFormData类中的appendPart函数最终目的就是给bodyStream中HTTPBodyParts添加一个AFHTTPBodyPart对象,如下代码:

  1. //各种类型的简直对追加到会调用到这里
  2. - (void)appendPartWithHeaders:(NSDictionary *)headers
  3. body:(NSData *)body
  4. {
  5. NSParameterAssert(body);
  6.  
  7. AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
  8. bodyPart.stringEncoding = self.stringEncoding;
  9. bodyPart.headers = headers;
  10. bodyPart.boundary = self.boundary;
  11. bodyPart.bodyContentLength = [body length];
  12. bodyPart.body = body;
  13.  
  14. [self.bodyStream appendHTTPBodyPart:bodyPart];
  15. }
  1. - (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart {
  2. [self.HTTPBodyParts addObject:bodyPart];
  3. }

也就是说所有的body消息都放在了HTTPBodyParts中,在操作字节流的时候,我们通过遍历这个数组,拼凑出http body的格式,然后上传给服务端。

我们看AFMultipartBodyStream类中定义的-(NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)length,这个方法是对NSInputStream类的方法的重写,为什么要重写呢,我们先来看一下 NSInputStream的常规用法。

要求,通过NSInputStream实现大文件上传,参考的网上,我们可以这么做:

地址:https://blog.csdn.net/u010576399/article/details/51180331

我们截取关键地方:

看代码,我们看到有一个while循环,每次fileStream read若干字节到readBUffer,最后都追加到了body中,当文件流读取结束或者出错误,结束while循环。

所以由此我们可以推断出:NSURLRequest底层也是有一个while循环,然后调用NSInputStream的read方法读取字节流,这里我们重写了这个read方法,那么读取的时候就会调用我们自己写的read方法,重写的read方法为如下代码:

  1. //读取字节的方法,把本地的内容读到buffer中,此方法由NSURLRequest调用,这里相当于重写
  2. - (NSInteger)read:(uint8_t *)buffer
  3. maxLength:(NSUInteger)length
  4. {
  5. // [super read:buffer maxLength:length]; 默认方法
  6.  
  7. NSLog (@"%@",[NSThread currentThread]);
  8. //// 输入流关闭,无法获取数据,返回子节长度为0
  9. if ([self streamStatus] == NSStreamStatusClosed) {
  10. return ;
  11. }
  12.  
  13. NSInteger totalNumberOfBytesRead = ;
  14. // length在mac 64上为32768
  15. // 每次读取32768的大小
  16. // while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) {
  17. while ((NSUInteger)totalNumberOfBytesRead < length) {
  18. // 如果当前读取的body不存在或者body没有可读字节
  19. //如果当前的HTTPBodyPart读取完成,就读取下一个;
  20. // HTTPBodyPartEnumerator(一个枚举)
  21. if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
  22. //把下一个body赋值给当前的body 如果下一个为nil 就退出循环
  23. if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
  24. break;
  25. }
  26. } else {
  27. // 当前body存在 且没有读完 且读取长度还小于32768
  28. // 剩余可读文件的大小
  29. NSUInteger maxLength = length - (NSUInteger)totalNumberOfBytesRead;
  30. // 调用bodypart的接口
  31. NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength];
  32. //读取出错
  33. if (numberOfBytesRead == -) {
  34. self.streamError = self.currentHTTPBodyPart.inputStream.streamError;
  35. break;
  36. } else {
  37. // totalNumberOfBytesRead当前读取的字节,作为下一次读取的起始字节
  38. totalNumberOfBytesRead += numberOfBytesRead;
  39.  
  40. // 延迟
  41. if (self.delay > 0.0f) {
  42. [NSThread sleepForTimeInterval:self.delay];
  43. }
  44. }
  45. }
  46. }
  47. //返回已经读取的字节大小,如果不为0或者-1,NSURLRequest会重新调用read方法,表示继续读取
  48. return totalNumberOfBytesRead;
  49. }

这个方法就是NSURLRequest 的while循环里调用的read方法。

这个read方法里面还有一个while,这个while是用来遍历httpBodyParts数组,用来吧数组里面的httpBodyPart都读取到buffer中,供NSURLRequst组装body消息体。

标红的方法为重点方法,进入看一下:

  1. //单个bodyPart的读取
  2. - (NSInteger)read:(uint8_t *)buffer
  3. maxLength:(NSUInteger)length
  4. {
  5. NSInteger totalNumberOfBytesRead = ;
  6. // 使用分割符将对应的bodyPart封装起来
  7. if (_phase == AFEncapsulationBoundaryPhase) {
  8. NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding];
  9.  
  10. totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
  11. }
  12. //// 读取bodyPart的header部分,使用stringForHeaders获取对应的header
  13. if (_phase == AFHeaderPhase) {
  14. NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding];
  15.  
  16. totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
  17. }
  18. //// 内容主体,直接写入到buffer中
  19. if (_phase == AFBodyPhase) {
  20. NSInteger numberOfBytesRead = ;
  21. // inputStream使用系统自带方法读取
  22. numberOfBytesRead = [self.inputStream read:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
  23. if (numberOfBytesRead == -) {
  24. return -;
  25. } else {
  26. totalNumberOfBytesRead += numberOfBytesRead;
  27. // 内容读取完成更换Phase
  28. if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) {
  29. [self transitionToNextPhase];
  30. }
  31. }
  32. }
  33. // 如果是最后一个bodyPart队形,在末尾加上分隔符
  34. if (_phase == AFFinalBoundaryPhase) {
  35. NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]);
  36.  
  37. totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
  38. }
  39.  
  40. return totalNumberOfBytesRead;
  41. }

这是对单个bodyPart的读取,bodyPart分为4块,如图:

这是一块上传附件的消息体片段,其余消息类似,read方法通过分别读取这四块内容加到buffer中。其中1,2,4 用了readData方法,3用了NSInputStream默认的方法。

下面看一下readData方法定义:

  1. - (NSInteger)readData:(NSData *)data
  2. intoBuffer:(uint8_t *)buffer
  3. maxLength:(NSUInteger)length
  4. {
  5. /*_phaseReadOffset这个属性设计的很巧妙,当buffer空间不够的时候,requst会重新分配buffer,
  6. _phaseReadOffset用来记录上次读的索引,等buffer重新分配够空间后,接着读
  7. */
  8. NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length));
  9. [data getBytes:buffer range:range];////--Boundary+7586B2B18E70A6B1\r\n
  10.  
  11. _phaseReadOffset += range.length;
  12.  
  13. if (((NSUInteger)_phaseReadOffset) >= [data length]) {
  14. [self transitionToNextPhase];
  15. }
  16.  
  17. return (NSInteger)range.length;
  18. }

当读取完了一块之后,调用transitionToNextphase方法,如果没有读取完,比如NSURLRequst每次分配的buffer字节不够了,就会返回这次读取的字节数,然后NSURLRequst通过while循环再次读取,_phaseReadOffset会记录上次的读取索引结果,然后下次接着读。

看下transitionToNextphase的定义:

  1. - (BOOL)transitionToNextPhase {
  2. if (![[NSThread currentThread] isMainThread]) {
  3. dispatch_sync(dispatch_get_main_queue(), ^{
  4. [self transitionToNextPhase];
  5. });
  6. return YES;
  7. }
  8. NSLog(@"当前线程=%@",[NSThread currentThread]);
  9. switch (_phase) {
  10. case AFEncapsulationBoundaryPhase:
  11. _phase = AFHeaderPhase;
  12. break;
  13. case AFHeaderPhase:
  14. [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  15. [self.inputStream open];
  16. _phase = AFBodyPhase;
  17. break;
  18. case AFBodyPhase:
  19. [self.inputStream close];
  20. _phase = AFFinalBoundaryPhase;
  21. break;
  22. case AFFinalBoundaryPhase:
  23. default:
  24. _phase = AFEncapsulationBoundaryPhase;
  25. break;
  26. }
  27. _phaseReadOffset = ;
  28.  
  29. return YES;
  30. }

总结:以上就是分析上传时候NSURLRequest的生成和处理过程,其实现方法可以说是一个对POST请求的在此封装。传输多种参数,多种资料型态混合的信息时会使用到multipart协议。

参考资料:

https://blog.csdn.net/cishengchangan/article/details/51939923

https://blog.csdn.net/lizhengwei1989/article/details/75635261

AFNetWorking 上传功能使用及源码分析的更多相关文章

  1. 史上最全的 Redux 源码分析

    前言 用 React + Redux 已经一段时间了,记得刚开始用Redux 的时候感觉非常绕,总搞不起里面的关系,如果大家用一段时间Redux又看了它的源码话,对你的理解会有很大的帮助.看完后,在回 ...

  2. 史上最全的JFinal源码分析(不间断更新)

    打算 开始 写 这么 一个系列,希望 大家 喜欢,学习 本来就是 一个查漏补缺的过程,希望大家能提出建议.本篇 文章 是整个目录的向导,希望 大家 喜欢.本文 将以 包的形式跟大家做向导. Handl ...

  3. v79.01 鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上) | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(用户态锁篇) | 如何使用快锁Futex(上) 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) ...

  4. Spring源码分析——资源访问利器Resource之实现类分析

    今天来分析Spring的资源接口Resource的各个实现类.关于它的接口和抽象类,参见上一篇博文——Spring源码分析——资源访问利器Resource之接口和抽象类分析 一.文件系统资源 File ...

  5. UiAutomator源码分析之UiAutomatorBridge框架

    上一篇文章<UIAutomator源码分析之启动和运行>我们描述了uitautomator从命令行运行到加载测试用例运行测试的整个流程,过程中我们也描述了UiAutomatorBridge ...

  6. UiAutomator源码分析之获取控件信息

    根据上一篇文章<UiAutomator源码分析之注入事件>开始时提到的计划,这一篇文章我们要分析的是第二点: 如何获取控件信息 我们在测试脚本中初始化一个UiObject的时候通常是像以下 ...

  7. UiAutomator源码分析之注入事件

    上一篇文章<UiAutomator源码分析之UiAutomatorBridge框架>中我们把UiAutomatorBridge以及它相关的类进行的描述,往下我们会尝试根据两个实例将这些类给 ...

  8. Monkey源码分析之事件源

    上一篇文章<Monkey源码分析之运行流程>给出了monkey运行的整个流程,让我们有一个概貌,那么往后的文章我们会尝试进一步的阐述相关的一些知识点. 这里先把整个monkey类的结构图给 ...

  9. Monkey源码分析之事件注入

    本系列的上一篇文章<Monkey源码分析之事件源>中我们描述了monkey是怎么从事件源取得命令,然后将命令转换成事件放到事件队列里面的,但是到现在位置我们还没有了解monkey里面的事件 ...

随机推荐

  1. CloudStack学习-3

    此次试验主要是CloudStack结合openvswitch 背景介绍 之所以引入openswitch,是因为如果按照之前的方式,一个网桥占用一个vlan,假如一个zone有20个vlan,那么岂不是 ...

  2. sql server 附加只有mdf的数据库文件

    有时候SQL Server意外断电会导致SQL Server的ldf日志文件丢失或者损坏,这个时候你如果直接附加mdf文件到SQL Server会失败,这里提供一个方法可以还原只有mdf的数据库文件, ...

  3. 用 .gitlab-ci.yml 配置 gitlab 的任务(job)

    官方说明:https://docs.gitlab.com/ee/ci/yaml/

  4. TypeScript 之 基础类型、高级类型

    基础类型:https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/Basic%20Types.html 高级类型:https ...

  5. pycharm开发django项目 static报404解决方法

    settings文件中确保有以下配置 # Static files (CSS, JavaScript, Images)# https://docs.djangoproject.com/en/1.10/ ...

  6. mysql程序之mysqladmin详解

    mysqladmin命令 mysqladmin是执行管理操作的客户端.您可以使用它来检查服务器的配置和当前状态,以创建和删除数据库等 用法: mysqladmin [OPTIONS] command ...

  7. C#:匿名类型

    匿名类型和var关键字是Visual C# 3.0提供的一个新特性,var是隐式类型而并不是类型javascript中的var. var user = new { Id = 1, Name = &qu ...

  8. msp430学习笔记-USART

    本文引用:http://bbs.ednchina.com/BLOG_ARTICLE_3013784.HTM MSP430F149有两个USART通讯端口,其性能完全一样,每个通讯口可通过RS232和R ...

  9. HMM(隐马尔科夫模型)与分词、词性标注、命名实体识别

    转载自 http://www.cnblogs.com/skyme/p/4651331.html HMM(隐马尔可夫模型)是用来描述隐含未知参数的统计模型,举一个经典的例子:一个东京的朋友每天根据天气{ ...

  10. python打包为独立可执行程序

    linux下 pip install pyinstaller 针对需要的项目 pyinstaller -F -w ./xxx.py 即可